2 # -*- coding: utf-8 -*-
5 # Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
6 # This file is part of openvim
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
13 # http://www.apache.org/licenses/LICENSE-2.0
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
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact with: nfvlabs@tid.es
26 This is the thread for the http server North API.
27 Two thread will be launched, with normal and administrative permissions.
37 from netaddr
import IPNetwork
38 from jsonschema
import validate
as js_v
, exceptions
as js_e
39 import host_thread
as ht
40 import dhcp_thread
as dt
41 import openflow_thread
as oft
44 __author__
= "Alfonso Tierno, Leonardo Mirabal"
45 __date__
= "$06-Feb-2017 12:07:15$"
46 __version__
= "0.5.29-r549"
47 version_date
= "Sep 2018"
48 database_version
= 23 #needed database schema version
50 HTTP_Bad_Request
= 400
51 HTTP_Unauthorized
= 401
54 HTTP_Method_Not_Allowed
= 405
55 HTTP_Not_Acceptable
= 406
56 HTTP_Request_Timeout
= 408
58 HTTP_Service_Unavailable
= 503
59 HTTP_Internal_Server_Error
= 500
62 def 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
66 'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
67 'items': tuple of keys to convert
71 if type(data
) is dict:
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
)
76 if type(data
[k
]) is str:
77 if data
[k
] == "false":
79 elif data
[k
] == "true":
81 if type(data
) is tuple or type(data
) is list:
83 if type(k
) is dict or type(k
) is tuple or type(k
) is list:
84 convert_boolean(k
, items
)
88 class ovimException(Exception):
89 def __init__(self
, message
, http_code
=HTTP_Bad_Request
):
90 self
.http_code
= http_code
91 Exception.__init
__(self
, message
)
95 running_info
= {} #TODO OVIM move the info of running threads from config_dic to this static variable
98 def __init__(self
, configuration
):
99 self
.config
= configuration
100 self
.logger_name
= configuration
.get("logger_name", "openvim")
101 self
.logger
= logging
.getLogger(self
.logger_name
)
103 self
.db
= self
._create
_database
_connection
()
104 self
.of_test_mode
= False
106 def _create_database_connection(self
):
107 db
= vim_db
.vim_db((self
.config
["network_vlan_range_start"], self
.config
["network_vlan_range_end"]),
108 self
.logger_name
+ ".db", self
.config
.get('log_level_db'))
109 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']) )
123 def get_version_date():
127 def get_database_version():
128 return database_version
131 def _check_dhcp_data_integrity(network
):
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
137 if "cidr" in network
:
138 cidr
= network
["cidr"]
139 ip_tools
= IPNetwork(cidr
)
140 cidr_len
= ip_tools
.prefixlen
144 ips
= IPNetwork(cidr
)
145 if "dhcp_first_ip" not in network
:
146 network
["dhcp_first_ip"] = str(ips
[3])
147 if "dhcp_last_ip" not in network
:
148 network
["dhcp_last_ip"] = str(ips
[-2])
149 if "gateway_ip" not in network
:
150 network
["gateway_ip"] = str(ips
[1])
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}$"}
160 js_v(uuid
, id_schema
)
162 except js_e
.ValidationError
:
165 def start_service(self
):
170 global database_version
171 # if self.running_info:
172 # return #TODO service can be checked and rebuild broken threads
173 r
= self
.db
.get_db_version()
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"
179 db_path
+= "/../database_utils"
182 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
))
188 self
.logger
.critical("Starting ovim server version: '{} {}' database version '{}'".format(
189 self
.get_version(), self
.get_version_date(), self
.get_database_version()))
190 # create database connection for openflow threads
191 self
.config
["db"] = self
._create
_database
_connection
()
193 self
.of_test_mode
= False if self
.config
['mode'] == 'normal' or self
.config
['mode'] == "OF only" else True
195 # Create one thread for each host
196 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
197 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
198 host_develop_bridge_iface
= self
.config
.get('development_bridge', None)
200 # get host list from data base before starting threads
201 r
, hosts
= self
.db
.get_table(SELECT
=('name', 'ip_name', 'user', 'uuid', 'hypervisors', 'password', 'keyfile'),
202 FROM
='hosts', WHERE
={'status': 'ok'}) #Unikernels extension
204 raise ovimException("Cannot get hosts from database {}".format(hosts
))
206 self
.config
['host_threads'] = {}
209 thread
= ht
.host_thread(name
=host
['name'], user
=host
['user'], host
=host
['ip_name'], db
=self
.config
["db"],
210 password
=host
['password'],
211 keyfile
=host
.get('keyfile', self
.config
["host_ssh_keyfile"]),
213 image_path
=self
.config
['host_image_path'],
214 version
=self
.config
['version'], host_id
=host
['uuid'],
215 develop_mode
=host_develop_mode
,
216 develop_bridge_iface
=host_develop_bridge_iface
,
217 hypervisors
=host
['hypervisors'], #Unikernels extension
218 logger_name
=self
.logger_name
+ ".host." + host
['name'],
219 debug
=self
.config
.get('log_level_host'))
222 thread
.check_connectivity()
223 except Exception as e
:
224 self
.logger
.critical('Error detected for compute = {} with ip = {}'
225 .format(host
['name'], host
['ip_name']))
227 self
.config
['host_threads'][host
['uuid']] = thread
229 # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge,
232 self
.config
['dhcp_nets'] = []
233 self
.config
['bridge_nets'] = []
234 for bridge
, vlan_speed
in self
.config
["bridge_ifaces"].items():
235 # skip 'development_bridge'
236 if self
.config
['mode'] == 'development' and self
.config
['development_bridge'] == bridge
:
238 self
.config
['bridge_nets'].append([bridge
, vlan_speed
[0], vlan_speed
[1], None])
240 # check if this bridge is already used (present at database) for a network)
241 used_bridge_nets
= []
242 for brnet
in self
.config
['bridge_nets']:
243 r
, nets
= self
.db
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'provider': "bridge:" + brnet
[0]})
245 brnet
[3] = nets
[0]['uuid']
246 used_bridge_nets
.append(brnet
[0])
247 if self
.config
.get("dhcp_server"):
248 if brnet
[0] in self
.config
["dhcp_server"]["bridge_ifaces"]:
249 self
.config
['dhcp_nets'].append(nets
[0]['uuid'])
250 if len(used_bridge_nets
) > 0:
251 self
.logger
.info("found used bridge nets: " + ",".join(used_bridge_nets
))
252 # get nets used by dhcp
253 if self
.config
.get("dhcp_server"):
254 for net
in self
.config
["dhcp_server"].get("nets", ()):
255 r
, nets
= self
.db
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'name': net
})
257 self
.config
['dhcp_nets'].append(nets
[0]['uuid'])
260 self
._start
_ofc
_default
_task
()
262 # OFC per tenant in DB
263 self
._start
_of
_db
_tasks
()
265 # create dhcp_server thread
266 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
267 dhcp_params
= self
.config
.get("dhcp_server")
269 thread
= dt
.dhcp_thread(dhcp_params
=dhcp_params
, test
=host_test_mode
, dhcp_nets
=self
.config
["dhcp_nets"],
270 db
=self
.config
["db"],
271 logger_name
=self
.logger_name
+ ".dhcp",
272 debug
=self
.config
.get('log_level_of'))
274 self
.config
['dhcp_thread'] = thread
278 # create ovs dhcp thread
279 result
, content
= self
.db
.get_table(FROM
='nets')
281 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
282 raise ovimException(str(content
), -result
)
285 net_type
= net
['type']
286 if net
['status'] != "INACTIVE" and (net_type
== 'bridge_data' or net_type
== 'bridge_man') and \
287 net
["provider"][:4] == 'OVS:' and net
["enable_dhcp"] == "true":
289 config_routes
= net
.get('routes')
291 routes
= yaml
.safe_load(config_routes
)
295 config_dns
= net
.get('dns')
297 dns
= yaml
.safe_load(config_dns
)
301 links
= net
.get('links')
303 links
= yaml
.safe_load(net
.get('links'))
304 if net
.get('enable_dhcp'):
305 self
.launch_dhcp_server(net
.get('vlan'),
306 net
.get('dhcp_first_ip'),
307 net
.get('dhcp_last_ip'),
309 net
.get('gateway_ip'),
312 self
.launch_link_bridge_to_ovs(net
['vlan'], net
.get('gateway_ip'), net
.get('cidr'), links
, routes
)
313 if net
["status"] == "ERROR":
314 self
.db
.update_rows("nets", UPDATE
={"status": "ACTIVE", "last_error": None},
315 WHERE
={"uuid": net
["uuid"]})
316 except Exception as e
:
317 self
.logger
.error("Fail at launching dhcp server for net_id='%s' net_name='%s': %s",
318 net
["uuid"], net
["name"], str(e
))
319 self
.db
.update_rows("nets", UPDATE
={"status": "ERROR",
320 "last_error": "Fail at launching dhcp server: " + str(e
)},
321 WHERE
={"uuid": net
["uuid"]})
323 def _start_of_db_tasks(self
):
325 Start ofc task for existing ofcs in database
329 ofcs
= self
.get_of_controllers()
332 of_conn
= self
._load
_of
_module
(ofc
)
333 # create ofc thread per of controller
334 self
._create
_ofc
_task
(ofc
['uuid'], ofc
['dpid'], of_conn
)
336 def _create_ofc_task(self
, ofc_uuid
, dpid
, of_conn
):
338 Create an ofc thread for handle each sdn controllers
339 :param ofc_uuid: sdn controller uuid
340 :param dpid: sdn controller dpid
341 :param of_conn: OF_conn module
344 if 'ofcs_thread' not in self
.config
and 'ofcs_thread_dpid' not in self
.config
:
346 ofcs_thread_dpid
= []
348 ofcs_threads
= self
.config
['ofcs_thread']
349 ofcs_thread_dpid
= self
.config
['ofcs_thread_dpid']
351 if ofc_uuid
not in ofcs_threads
:
352 ofc_thread
= self
._create
_ofc
_thread
(of_conn
, ofc_uuid
)
353 if ofc_uuid
== "Default":
354 self
.config
['of_thread'] = ofc_thread
356 ofcs_threads
[ofc_uuid
] = ofc_thread
357 self
.config
['ofcs_thread'] = ofcs_threads
359 ofcs_thread_dpid
.append({dpid
: ofc_thread
})
360 self
.config
['ofcs_thread_dpid'] = ofcs_thread_dpid
362 def _start_ofc_default_task(self
):
364 Create default ofc thread
366 if 'of_controller' not in self
.config \
367 and 'of_controller_ip' not in self
.config \
368 and 'of_controller_port' not in self
.config \
369 and 'of_controller_dpid' not in self
.config
:
374 db_config
['ip'] = self
.config
.get('of_controller_ip')
375 db_config
['port'] = self
.config
.get('of_controller_port')
376 db_config
['dpid'] = self
.config
.get('of_controller_dpid')
377 db_config
['type'] = self
.config
.get('of_controller')
378 db_config
['user'] = self
.config
.get('of_user')
379 db_config
['password'] = self
.config
.get('of_password')
381 # create connector to the openflow controller
382 # load other parameters starting by of_ from config dict in a temporal dict
384 of_conn
= self
._load
_of
_module
(db_config
)
385 # create openflow thread
386 self
._create
_ofc
_task
("Default", db_config
['dpid'], of_conn
)
388 def _load_of_module(self
, db_config
):
390 import python module for each SDN controller supported
391 :param db_config: SDN dn information
395 raise ovimException("No module found it", HTTP_Internal_Server_Error
)
400 if self
.of_test_mode
:
401 return openflow_conn
.OfTestConnector({"name": db_config
['type'],
402 "dpid": db_config
['dpid'],
403 "of_debug": self
.config
['log_level_of']})
407 temp_dict
['of_ip'] = db_config
['ip']
408 temp_dict
['of_port'] = db_config
['port']
409 temp_dict
['of_dpid'] = db_config
['dpid']
410 temp_dict
['of_controller'] = db_config
['type']
411 temp_dict
['of_user'] = db_config
.get('user')
412 temp_dict
['of_password'] = db_config
.get('password')
414 temp_dict
['of_debug'] = self
.config
['log_level_of']
416 if temp_dict
['of_controller'] == 'opendaylight':
419 module
= temp_dict
['of_controller']
421 if module
not in ovim
.of_module
:
423 pkg
= __import__("osm_openvim." + module
)
424 of_conn_module
= getattr(pkg
, module
)
425 ovim
.of_module
[module
] = of_conn_module
426 self
.logger
.debug("Module load from {}".format("osm_openvim." + module
))
427 except Exception as e
:
428 self
.logger
.error("Cannot open openflow controller module of type '%s'", module
)
429 raise ovimException("Cannot open openflow controller of type module '{}'"
430 "Revise it is installed".format(module
),
431 HTTP_Internal_Server_Error
)
433 of_conn_module
= ovim
.of_module
[module
]
434 return of_conn_module
.OF_conn(temp_dict
)
435 except Exception as e
:
436 self
.logger
.error("Cannot open the Openflow controller '%s': %s", type(e
).__name
__, str(e
))
437 raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e
).__name
__, str(e
)),
438 HTTP_Internal_Server_Error
)
440 def _create_ofc_thread(self
, of_conn
, ofc_uuid
="Default"):
442 Create and launch a of thread
445 # create openflow thread
447 #if 'of_controller_nets_with_same_vlan' in self.config:
448 # ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
450 # ofc_net_same_vlan = False
451 ofc_net_same_vlan
= False
453 thread
= oft
.openflow_thread(ofc_uuid
, of_conn
, of_test
=self
.of_test_mode
, db
=self
.config
["db"],
454 pmp_with_same_vlan
=ofc_net_same_vlan
,
455 logger_name
=self
.logger_name
+ ".ofc." + ofc_uuid
,
456 debug
=self
.config
.get('log_level_of'))
457 #r, c = thread.OF_connector.obtain_port_correspondence()
459 # raise ovimException("Cannot get openflow information %s", c)
463 def stop_service(self
):
464 threads
= self
.config
.get('host_threads', {})
465 if 'of_thread' in self
.config
:
466 threads
['of'] = (self
.config
['of_thread'])
467 if 'ofcs_thread' in self
.config
:
468 ofcs_thread
= self
.config
['ofcs_thread']
469 for ofc
in ofcs_thread
:
470 threads
[ofc
] = ofcs_thread
[ofc
]
472 if 'dhcp_thread' in self
.config
:
473 threads
['dhcp'] = (self
.config
['dhcp_thread'])
475 for thread_id
, thread
in threads
.items():
476 if thread_id
== 'openvim_controller':
478 thread
.insert_task("exit")
479 for thread_id
, thread
in threads
.items():
480 if thread_id
== 'openvim_controller':
484 def get_networks(self
, columns
=None, db_filter
={}, limit
=None):
486 Retreive networks available
487 :param columns: List with select query parameters
488 :param db_filter: List with where query parameters
489 :param limit: Query limit result
492 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='nets', WHERE
=db_filter
, LIMIT
=limit
)
495 raise ovimException(str(content
), -result
)
497 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
501 def show_network(self
, network_id
, db_filter
={}, skip_on_not_found
=False):
503 Get network from DB by id
504 :param network_id: net Id
505 :param db_filter: List with where query parameters
510 raise ovimException("Not network id was not found")
511 db_filter
['uuid'] = network_id
513 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
=db_filter
, LIMIT
=100)
516 raise ovimException(str(content
), -result
)
518 if skip_on_not_found
:
520 raise ovimException("show_network network '%s' not found" % network_id
, HTTP_Not_Found
)
522 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
524 result
, ports
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
525 WHERE
={'net_id': network_id
}, LIMIT
=100)
527 content
[0]['ports'] = ports
528 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
530 result
, flows
= self
.db
.get_table(FROM
='of_flows', SELECT
=('priority', 'vlan_id', 'ingress_port', 'src_mac', 'dst_mac', 'actions'),
531 WHERE
={'net_id': network_id
}, LIMIT
=100)
533 content
[0]['flows'] = flows
536 def new_network(self
, network
):
541 tenant_id
= network
.get('tenant_id')
544 result
, _
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
, "enabled": True})
546 raise ovimException("set_network error, no tenant founded", -result
)
550 net_provider
= network
.get('provider')
551 net_type
= network
.get('type')
552 net_vlan
= network
.get("vlan")
553 net_bind_net
= network
.get("bind_net")
554 net_bind_type
= network
.get("bind_type")
555 net_region
= network
.get("region")
556 name
= network
["name"]
558 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
559 vlan_index
= name
.rfind(":")
560 if not net_bind_net
and not net_bind_type
and vlan_index
> 1:
562 vlan_tag
= int(name
[vlan_index
+ 1:])
563 if not vlan_tag
and vlan_tag
< 4096:
564 net_bind_net
= name
[:vlan_index
]
565 net_bind_type
= "vlan:" + name
[vlan_index
+ 1:]
570 # look for a valid net
571 if self
._check
_valid
_uuid
(net_bind_net
):
572 net_bind_key
= "uuid"
574 net_bind_key
= "name"
575 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
577 raise ovimException(' getting nets from db ' + content
, HTTP_Internal_Server_Error
)
579 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
581 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
582 network
["bind_net"] = content
[0]["uuid"]
585 if net_bind_type
[0:5] != "vlan:":
586 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
587 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
588 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
590 network
["bind_type"] = net_bind_type
593 if net_provider
[:9] == "openflow:":
595 if net_type
!= "ptp" and net_type
!= "data":
596 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
602 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
603 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
604 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
606 net_type
= 'bridge_man'
609 net_type
= 'bridge_man'
612 if net_provider
[:7] == 'bridge:':
613 # check it is one of the pre-provisioned bridges
614 bridge_net_name
= net_provider
[7:]
615 for brnet
in self
.config
['bridge_nets']:
616 if brnet
[0] == bridge_net_name
: # free
618 raise ovimException("invalid 'provider:physical', "
619 "bridge '%s' is already used" % bridge_net_name
, HTTP_Conflict
)
623 # if bridge_net==None:
624 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
625 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
628 elif self
.config
['network_type'] == 'bridge' and (net_type
== 'bridge_data' or net_type
== 'bridge_man'):
629 # look for a free precreated nets
630 for brnet
in self
.config
['bridge_nets']:
631 if not brnet
[3]: # free
633 if net_type
== 'bridge_man': # look for the smaller speed
634 if brnet
[2] < bridge_net
[2]:
636 else: # look for the larger speed
637 if brnet
[2] > bridge_net
[2]:
643 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
644 "will overcome this limit", HTTP_Bad_Request
)
646 self
.logger
.debug("using net " + bridge_net
)
647 net_provider
= "bridge:" + bridge_net
[0]
648 net_vlan
= bridge_net
[1]
649 elif net_type
== 'bridge_data' or net_type
== 'bridge_man' and self
.config
['network_type'] == 'ovs':
652 if net_type
== "data" or net_type
== "ptp":
653 net_region
= "__DATA__"
654 elif net_provider
== "OVS":
655 net_region
= "__OVS__"
656 if not net_vlan
and (net_type
== "data" or net_type
== "ptp" or net_provider
== "OVS"):
657 net_vlan
= self
.db
.get_free_net_vlan(net_region
)
659 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error
)
660 if net_provider
== 'OVS':
661 net_provider
= 'OVS' + ":" + str(net_vlan
)
663 network
['provider'] = net_provider
664 network
['type'] = net_type
665 network
['vlan'] = net_vlan
666 network
['region'] = net_region
667 dhcp_integrity
= True
668 if network
.get('enable_dhcp'):
669 dhcp_integrity
= self
._check
_dhcp
_data
_integrity
(network
)
671 if network
.get('links'):
672 network
['links'] = yaml
.safe_dump(network
['links'], default_flow_style
=True, width
=256)
673 if network
.get('dns'):
674 network
['dns'] = yaml
.safe_dump(network
['dns'], default_flow_style
=True, width
=256)
675 if network
.get('routes'):
676 network
['routes'] = yaml
.safe_dump(network
['routes'], default_flow_style
=True, width
=256)
678 result
, content
= self
.db
.new_row('nets', network
, True, True)
679 if result
>= 0: # and dhcp_integrity:
681 bridge_net
[3] = content
682 if self
.config
.get("dhcp_server") and self
.config
['network_type'] == 'bridge':
683 if network
["name"] in self
.config
["dhcp_server"].get("nets", ()):
684 self
.config
["dhcp_nets"].append(content
)
685 self
.logger
.debug("dhcp_server: add new net", content
)
686 elif bridge_net
and bridge_net
[0] in self
.config
["dhcp_server"].get("bridge_ifaces", ()):
687 self
.config
["dhcp_nets"].append(content
)
688 self
.logger
.debug("dhcp_server: add new net", content
, content
)
691 raise ovimException("Error creating network: {}".format(content
), -result
)
693 # TODO kei change update->edit
695 def edit_network(self
, network_id
, network
):
697 Update entwork data byt id
700 # Look for the previous data
701 where_
= {'uuid': network_id
}
702 result
, network_old
= self
.db
.get_table(FROM
='nets', WHERE
=where_
)
704 raise ovimException("Error updating network %s" % network_old
, HTTP_Internal_Server_Error
)
706 raise ovimException('network %s not found' % network_id
, HTTP_Not_Found
)
708 nbports
, content
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
709 WHERE
={'net_id': network_id
}, LIMIT
=100)
711 raise ovimException("http_put_network_id error %d %s" % (result
, network_old
), HTTP_Internal_Server_Error
)
713 if 'type' in network
and network
['type'] != network_old
[0]['type']:
714 raise ovimException("Can not change type of network while having ports attached",
715 HTTP_Method_Not_Allowed
)
716 if 'vlan' in network
and network
['vlan'] != network_old
[0]['vlan']:
717 raise ovimException("Can not change vlan of network while having ports attached",
718 HTTP_Method_Not_Allowed
)
721 net_provider
= network
.get('provider', network_old
[0]['provider'])
722 net_type
= network
.get('type', network_old
[0]['type'])
723 net_bind_net
= network
.get("bind_net")
724 net_bind_type
= network
.get("bind_type")
726 # look for a valid net
727 if self
._check
_valid
_uuid
(net_bind_net
):
728 net_bind_key
= "uuid"
730 net_bind_key
= "name"
731 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
733 raise ovimException('Getting nets from db ' + content
, HTTP_Internal_Server_Error
)
735 raise ovimException("bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
737 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
),
739 network
["bind_net"] = content
[0]["uuid"]
741 if net_bind_type
[0:5] != "vlan:":
742 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
743 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
744 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
747 if net_provider
[:9] == "openflow:":
748 if net_type
!= "ptp" and net_type
!= "data":
749 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request
)
751 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
752 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
753 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
755 # insert in data base
756 result
, content
= self
.db
.update_rows('nets', network
, WHERE
={'uuid': network_id
}, log
=True)
758 # if result > 0 and nbports>0 and 'admin_state_up' in network
759 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
764 self
.net_update_ofc_thread(network_id
)
765 except ovimException
as e
:
766 raise ovimException("Error while launching openflow rules in network '{}' {}"
767 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
768 except Exception as e
:
769 raise ovimException("Error while launching openflow rules in network '{}' {}"
770 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
772 if self
.config
.get("dhcp_server"):
773 if network_id
in self
.config
["dhcp_nets"]:
774 self
.config
["dhcp_nets"].remove(network_id
)
775 if network
.get("name", network_old
[0]["name"]) in self
.config
["dhcp_server"].get("nets", ()):
776 self
.config
["dhcp_nets"].append(network_id
)
778 net_bind
= network
.get("bind_type", network_old
[0]["bind_type"])
779 if net_bind
and net_bind
and net_bind
[:7] == "bridge:" and net_bind
[7:] in self
.config
["dhcp_server"].get(
780 "bridge_ifaces", ()):
781 self
.config
["dhcp_nets"].append(network_id
)
784 raise ovimException(content
, -result
)
786 def delete_network(self
, network_id
, idempotent
=True):
788 Delete network by network id
789 :param network_id: network id
792 net_data
= self
.show_network(network_id
, skip_on_not_found
=idempotent
)
793 if not net_data
: # network does not exist
796 # delete from the data base
797 result
, content
= self
.db
.delete_row('nets', network_id
)
800 raise ovimException("Network %s not found " % network_id
, HTTP_Not_Found
)
802 for brnet
in self
.config
['bridge_nets']:
803 if brnet
[3] == network_id
:
806 if self
.config
.get("dhcp_server") and network_id
in self
.config
["dhcp_nets"]:
807 self
.config
["dhcp_nets"].remove(network_id
)
809 if net_data
.get('enable_dhcp'):
810 dhcp_path
= self
.config
['ovs_controller_file_path']
811 dhcp_controller
= self
.get_dhcp_controller()
812 dhcp_controller
.delete_dhcp_server(net_data
['vlan'], network_id
, dhcp_path
)
813 dhcp_controller
.delete_dhcp_port(net_data
['vlan'], network_id
, dhcp_path
)
814 links
= yaml
.load(net_data
.get('links'))
816 links
= yaml
.load(net_data
.get('links'))
817 self
.delete_link_bridge_to_ovs(net_data
['vlan'], links
)
821 raise ovimException("Error deleting network '{}': {}".format(network_id
, content
), -result
)
823 def get_openflow_rules(self
, network_id
=None):
825 Get openflow id from DB
826 :param network_id: Network id, if none all networks will be retrieved
827 :return: Return a list with Openflow rules per net
833 where_
= {"net_id": network_id
}
834 result
, content
= self
.db
.get_table(
835 SELECT
=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
836 WHERE
=where_
, FROM
='of_flows')
839 raise ovimException(str(content
), -result
)
842 def edit_openflow_rules(self
, network_id
=None):
845 To make actions over the net. The action is to reinstall the openflow rules
846 network_id can be 'all'
847 :param network_id: Network id, if none all networks will be retrieved
848 :return : Number of nets updated
855 where_
= {"uuid": network_id
}
856 result
, content
= self
.db
.get_table(SELECT
=("uuid", "type"), WHERE
=where_
, FROM
='nets')
859 raise ovimException(str(content
), -result
)
862 if net
["type"] != "ptp" and net
["type"] != "data":
867 self
.net_update_ofc_thread(net
['uuid'])
868 except ovimException
as e
:
869 raise ovimException("Error updating network'{}' {}".format(net
['uuid'], str(e
)),
870 HTTP_Internal_Server_Error
)
871 except Exception as e
:
872 raise ovimException("Error updating network '{}' {}".format(net
['uuid'], str(e
)),
873 HTTP_Internal_Server_Error
)
877 def delete_openflow_rules(self
, ofc_id
=None):
879 To make actions over the net. The action is to delete ALL openflow rules
880 :return: return operation result
884 if 'Default' in self
.config
['ofcs_thread']:
885 r
, c
= self
.config
['ofcs_thread']['Default'].insert_task("clear-all")
887 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
889 elif ofc_id
in self
.config
['ofcs_thread']:
890 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("clear-all")
894 raise ovimException(str(c
), -r
)
896 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
899 def get_openflow_ports(self
, ofc_id
=None):
901 Obtain switch ports names of openflow controller
902 :return: Return flow ports in DB
905 if 'Default' in self
.config
['ofcs_thread']:
906 conn
= self
.config
['ofcs_thread']['Default'].OF_connector
908 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
910 elif ofc_id
in self
.config
['ofcs_thread']:
911 conn
= self
.config
['ofcs_thread'][ofc_id
].OF_connector
913 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
916 def get_ports(self
, columns
=None, filter={}, limit
=None):
917 # result, content = my.db.get_ports(where_)
918 result
, content
= self
.db
.get_table(SELECT
=columns
, WHERE
=filter, FROM
='ports', LIMIT
=limit
)
920 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
921 raise ovimException(str(content
), -result
)
923 convert_boolean(content
, ('admin_state_up',))
926 def new_port(self
, port_data
):
927 port_data
['type'] = 'external'
928 if port_data
.get('net_id'):
929 # check that new net has the correct type
930 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
932 raise ovimException(str(new_net
), -result
)
933 # insert in data base
934 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
936 if 'net_id' in port_data
:
938 self
.net_update_ofc_thread(port_data
['net_id'])
939 except ovimException
as e
:
940 raise ovimException("Cannot insert a task for updating network '{}' {}"
941 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
942 except Exception as e
:
943 raise ovimException("Cannot insert a task for updating network '{}' {}"
944 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
948 raise ovimException(str(uuid
), -result
)
950 def new_external_port(self
, port_data
):
952 Create new external port and check port mapping correspondence
953 :param port_data: port_data = {
954 'region': 'datacenter region',
955 'compute_node': 'compute node id',
956 'pci': 'pci port address',
959 'tenant_id': 'tenant id',
962 'ip_address': 'ip address - optional'}
966 port_data
['type'] = 'external'
968 if port_data
.get('net_id'):
969 # check that new net has the correct type
970 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
972 raise ovimException(str(new_net
), -result
)
973 # insert in data base
976 if port_data
.get('region'):
977 db_filter
['region'] = port_data
['region']
978 if port_data
.get('pci'):
979 db_filter
['pci'] = port_data
['pci']
980 if port_data
.get('compute_node'):
981 db_filter
['compute_node'] = port_data
['compute_node']
983 columns
= ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
984 port_mapping_data
= self
.get_of_port_mappings(columns
, db_filter
)
986 if not len(port_mapping_data
):
987 raise ovimException("No port mapping founded for '{}'".format(str(db_filter
)),
989 elif len(port_mapping_data
) > 1:
990 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
993 port_data
['ofc_id'] = port_mapping_data
[0]['ofc_id']
994 port_data
['switch_dpid'] = port_mapping_data
[0]['switch_dpid']
995 port_data
['switch_port'] = port_mapping_data
[0]['switch_port']
996 port_data
['switch_mac'] = port_mapping_data
[0]['switch_mac']
998 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
999 if 'region' in port_data
:
1000 del port_data
['region']
1001 if 'pci' in port_data
:
1002 del port_data
['pci']
1003 if 'compute_node' in port_data
:
1004 del port_data
['compute_node']
1006 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
1007 # set net status to BUILD
1008 self
.db
.update_rows('nets', {"status": "BUILD"}, WHERE
={'uuid': port_data
['net_id']})
1011 self
.net_update_ofc_thread(port_data
['net_id'], port_data
['ofc_id'])
1012 except ovimException
as e
:
1013 raise ovimException("Cannot insert a task for updating network '{}' {}".
1014 format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
1015 except Exception as e
:
1016 raise ovimException("Cannot insert a task for updating network '{}' {}"
1017 .format(port_data
['net_id'], e
), HTTP_Internal_Server_Error
)
1020 raise ovimException(str(uuid
), -result
)
1022 def net_update_ofc_thread(self
, net_id
, ofc_id
=None, switch_dpid
=None):
1024 Insert a update net task by net id or ofc_id for each ofc thread
1025 :param net_id: network id
1026 :param ofc_id: openflow controller id
1027 :param switch_dpid: switch dpid
1031 raise ovimException("No net_id received", HTTP_Internal_Server_Error
)
1034 c
= 'No valid ofc_id or switch_dpid received'
1037 ports
= self
.get_ports(filter={"net_id": net_id
})
1039 port_ofc_id
= port
.get('ofc_id', None)
1041 ofc_id
= port
['ofc_id']
1042 switch_dpid
= port
['switch_dpid']
1044 #TODO if not ofc_id: look at database table ofcs
1047 # If no ofc_id found it, default ofc_id is used.
1048 if not ofc_id
and not switch_dpid
:
1051 if ofc_id
and ofc_id
in self
.config
['ofcs_thread']:
1052 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("update-net", net_id
)
1055 ofcs_dpid_list
= self
.config
['ofcs_thread_dpid']
1056 for ofc_t
in ofcs_dpid_list
:
1057 if switch_dpid
in ofc_t
:
1058 r
, c
= ofc_t
[switch_dpid
].insert_task("update-net", net_id
)
1061 message
= "Cannot insert a task for updating network '{}', {}".format(net_id
, c
)
1062 self
.logger
.error(message
)
1063 raise ovimException(message
, HTTP_Internal_Server_Error
)
1065 def delete_port(self
, port_id
, idempotent
=False):
1066 # Look for the previous port data
1067 result
, ports
= self
.db
.get_table(WHERE
={'uuid': port_id
, "type": "external"}, FROM
='ports')
1069 raise ovimException("Cannot get port info from database: {}".format(ports
), http_code
=-result
)
1070 # delete from the data base
1071 result
, content
= self
.db
.delete_row('ports', port_id
)
1075 raise ovimException("External port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1077 raise ovimException("Cannot delete port from database: {}".format(content
), http_code
=-result
)
1079 net_id
= ports
[0].get('net_id', None)
1083 # set net status to BUILD
1084 self
.db
.update_rows('nets', {"status": "BUILD"}, WHERE
={'uuid': net_id
})
1086 self
.net_update_ofc_thread(net_id
, ofc_id
=ports
[0]["ofc_id"], switch_dpid
=ports
[0]["switch_dpid"])
1087 except ovimException
as e
:
1088 raise ovimException("Cannot insert a task for delete network '{}' {}".format(net_id
, str(e
)),
1089 HTTP_Internal_Server_Error
)
1090 except Exception as e
:
1091 raise ovimException("Cannot insert a task for delete network '{}' {}".format(net_id
, str(e
)),
1092 HTTP_Internal_Server_Error
)
1096 def edit_port(self
, port_id
, port_data
, admin
=True):
1097 # Look for the previous port data
1098 result
, content
= self
.db
.get_table(FROM
="ports", WHERE
={'uuid': port_id
})
1100 raise ovimException("Cannot get port info from database: {}".format(content
), http_code
=-result
)
1102 raise ovimException("Port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1107 if 'net_id' in port_data
:
1109 old_net
= port
.get('net_id', None)
1110 new_net
= port_data
['net_id']
1111 if old_net
!= new_net
:
1114 nets
.append(new_net
) # put first the new net, so that new openflow rules are created before removing the old ones
1116 nets
.append(old_net
)
1117 if port
['type'] == 'instance:bridge' or port
['type'] == 'instance:ovs':
1118 raise ovimException("bridge interfaces cannot be attached to a different net", http_code
=HTTP_Forbidden
)
1119 elif port
['type'] == 'external' and not admin
:
1120 raise ovimException("Needed admin privileges",http_code
=HTTP_Unauthorized
)
1122 # check that new net has the correct type
1123 result
, new_net_dict
= self
.db
.check_target_net(new_net
, None, port
['type'])
1125 raise ovimException("Error {}".format(new_net_dict
), http_code
=HTTP_Conflict
)
1126 # change VLAN for SR-IOV ports
1127 if result
>= 0 and port
["type"] == "instance:data" and port
["model"] == "VF": # TODO consider also VFnotShared
1129 port_data
["vlan"] = None
1131 port_data
["vlan"] = new_net_dict
["vlan"]
1132 # get host where this VM is allocated
1133 result
, content
= self
.db
.get_table(FROM
="instances", WHERE
={"uuid": port
["instance_id"]})
1135 host_id
= content
[0]["host_id"]
1137 # insert in data base
1139 result
, content
= self
.db
.update_rows('ports', port_data
, WHERE
={'uuid': port_id
}, log
=False)
1140 port
.update(port_data
)
1142 # Insert task to complete actions
1146 self
.net_update_ofc_thread(net_id
, port
["ofc_id"], switch_dpid
=port
["switch_dpid"])
1147 except ovimException
as e
:
1148 raise ovimException("Error updating network'{}' {}".format(net_id
, str(e
)),
1149 HTTP_Internal_Server_Error
)
1150 except Exception as e
:
1151 raise ovimException("Error updating network '{}' {}".format(net_id
, str(e
)),
1152 HTTP_Internal_Server_Error
)
1155 r
, v
= self
.config
['host_threads'][host_id
].insert_task("edit-iface", port_id
, old_net
, new_net
)
1157 self
.logger
.error("Error updating network '{}' {}".format(r
,v
))
1158 # TODO Do something if fails
1162 raise ovimException("Error {}".format(content
), http_code
=-result
)
1164 def new_of_controller(self
, ofc_data
):
1166 Create a new openflow controller into DB
1167 :param ofc_data: Dict openflow controller data
1168 :return: openflow controller dpid
1171 result
, ofc_uuid
= self
.db
.new_row('ofcs', ofc_data
, True, True)
1173 raise ovimException("New ofc Error %s" % ofc_uuid
, HTTP_Internal_Server_Error
)
1175 ofc_data
['uuid'] = ofc_uuid
1176 of_conn
= self
._load
_of
_module
(ofc_data
)
1177 self
._create
_ofc
_task
(ofc_uuid
, ofc_data
['dpid'], of_conn
)
1181 def edit_of_controller(self
, of_id
, ofc_data
):
1183 Edit an openflow controller entry from DB
1187 raise ovimException("No data received during uptade OF contorller", http_code
=HTTP_Internal_Server_Error
)
1189 old_of_controller
= self
.show_of_controller(of_id
)
1191 if old_of_controller
:
1192 result
, content
= self
.db
.update_rows('ofcs', ofc_data
, WHERE
={'uuid': of_id
}, log
=False)
1196 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1199 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1200 http_code
=HTTP_Internal_Server_Error
)
1202 def delete_of_controller(self
, of_id
):
1204 Delete an openflow controller from DB.
1205 :param of_id: openflow controller dpid
1209 ofc
= self
.show_of_controller(of_id
)
1211 result
, content
= self
.db
.delete_row("ofcs", of_id
)
1213 raise ovimException("Cannot delete ofc from database: {}".format(content
), http_code
=-result
)
1215 raise ovimException("ofc {} not found ".format(content
), http_code
=HTTP_Not_Found
)
1217 ofc_thread
= self
.config
['ofcs_thread'][of_id
]
1218 del self
.config
['ofcs_thread'][of_id
]
1219 for ofc_th
in self
.config
['ofcs_thread_dpid']:
1220 if ofc
['dpid'] in ofc_th
:
1221 self
.config
['ofcs_thread_dpid'].remove(ofc_th
)
1223 ofc_thread
.insert_task("exit")
1228 def show_of_controller(self
, uuid
):
1230 Show an openflow controller by dpid from DB.
1231 :param db_filter: List with where query parameters
1235 result
, content
= self
.db
.get_table(FROM
='ofcs', WHERE
={"uuid": uuid
}, LIMIT
=100)
1238 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid
),
1239 http_code
=HTTP_Not_Found
)
1241 raise ovimException("Openflow controller with uuid '{}' error".format(uuid
),
1242 http_code
=HTTP_Internal_Server_Error
)
1245 def get_of_controllers(self
, columns
=None, db_filter
={}, limit
=None):
1247 Show an openflow controllers from DB.
1248 :param columns: List with SELECT query parameters
1249 :param db_filter: List with where query parameters
1250 :param limit: result Limit
1253 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='ofcs', WHERE
=db_filter
, LIMIT
=limit
)
1256 raise ovimException(str(content
), -result
)
1260 def get_tenants(self
, columns
=None, db_filter
={}, limit
=None):
1262 Retrieve tenant list from DB
1263 :param columns: List with SELECT query parameters
1264 :param db_filter: List with where query parameters
1265 :param limit: result limit
1268 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=columns
, WHERE
=db_filter
, LIMIT
=limit
)
1270 raise ovimException('get_tenatns Error {}'.format(str(content
)), -result
)
1272 convert_boolean(content
, ('enabled',))
1275 def show_tenant_id(self
, tenant_id
):
1277 Get tenant from DB by id
1278 :param tenant_id: tenant id
1281 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid', 'name', 'description', 'enabled'),
1282 WHERE
={"uuid": tenant_id
})
1284 raise ovimException(str(content
), -result
)
1286 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1288 convert_boolean(content
, ('enabled',))
1291 def new_tentant(self
, tenant
):
1293 Create a tenant and store in DB
1294 :param tenant: Dictionary with tenant data
1295 :return: the uuid of created tenant. Raise exception upon error
1298 # insert in data base
1299 result
, tenant_uuid
= self
.db
.new_tenant(tenant
)
1304 raise ovimException(str(tenant_uuid
), -result
)
1306 def delete_tentant(self
, tenant_id
):
1308 Delete a tenant from the database.
1309 :param tenant_id: Tenant id
1310 :return: delete tenant id
1314 r
, tenants_flavors
= self
.db
.get_table(FROM
='tenants_flavors', SELECT
=('flavor_id', 'tenant_id'),
1315 WHERE
={'tenant_id': tenant_id
})
1317 tenants_flavors
= ()
1318 r
, tenants_images
= self
.db
.get_table(FROM
='tenants_images', SELECT
=('image_id', 'tenant_id'),
1319 WHERE
={'tenant_id': tenant_id
})
1323 result
, content
= self
.db
.delete_row('tenants', tenant_id
)
1325 raise ovimException("tenant '%s' not found" % tenant_id
, HTTP_Not_Found
)
1327 for flavor
in tenants_flavors
:
1328 self
.db
.delete_row_by_key("flavors", "uuid", flavor
['flavor_id'])
1329 for image
in tenants_images
:
1330 self
.db
.delete_row_by_key("images", "uuid", image
['image_id'])
1333 raise ovimException("Error deleting tenant '%s' " % tenant_id
, HTTP_Internal_Server_Error
)
1335 def edit_tenant(self
, tenant_id
, tenant_data
):
1337 Update a tenant data identified by tenant id
1338 :param tenant_id: tenant id
1339 :param tenant_data: Dictionary with tenant data
1343 # Look for the previous data
1344 result
, tenant_data_old
= self
.db
.get_table(FROM
='tenants', WHERE
={'uuid': tenant_id
})
1346 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id
, tenant_data_old
),
1347 HTTP_Internal_Server_Error
)
1349 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1351 # insert in data base
1352 result
, content
= self
.db
.update_rows('tenants', tenant_data
, WHERE
={'uuid': tenant_id
}, log
=True)
1356 raise ovimException(str(content
), -result
)
1358 def set_of_port_mapping(self
, of_maps
, ofc_id
=None, switch_dpid
=None, region
=None):
1360 Create new port mapping entry
1361 :param of_maps: List with port mapping information
1362 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1363 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1364 :param ofc_id: ofc id
1365 :param switch_dpid: switch dpid
1366 :param region: datacenter region id
1372 map['ofc_id'] = ofc_id
1374 map['switch_dpid'] = switch_dpid
1376 map['region'] = region
1378 map["pci"] = map["pci"].lower()
1380 for of_map
in of_maps
:
1381 result
, uuid
= self
.db
.new_row('of_port_mappings', of_map
, True)
1383 of_map
["uuid"] = uuid
1385 raise ovimException(str(uuid
), -result
)
1388 def clear_of_port_mapping(self
, db_filter
={}):
1390 Clear port mapping filtering using db_filter dict
1391 :param db_filter: Parameter to filter during remove process
1394 result
, content
= self
.db
.delete_row_by_dict(FROM
='of_port_mappings', WHERE
=db_filter
)
1399 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter
)),
1400 HTTP_Internal_Server_Error
)
1402 def get_of_port_mappings(self
, column
=None, db_filter
=None, db_limit
=None):
1404 Retrive port mapping from DB
1409 result
, content
= self
.db
.get_table(SELECT
=column
, WHERE
=db_filter
, FROM
='of_port_mappings', LIMIT
=db_limit
)
1412 self
.logger
.error("get_of_port_mappings Error %d %s", result
, content
)
1413 raise ovimException(str(content
), -result
)
1417 def get_dhcp_controller(self
):
1419 Create an host_thread object for manage openvim controller and not create a thread for itself
1420 :return: dhcp_host openvim controller object
1423 if 'openvim_controller' in self
.config
['host_threads']:
1424 return self
.config
['host_threads']['openvim_controller']
1427 controller_ip
= self
.config
['ovs_controller_ip']
1428 ovs_controller_user
= self
.config
.get('ovs_controller_user')
1430 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
1431 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
1433 dhcp_host
= ht
.host_thread(name
='openvim_controller', user
=ovs_controller_user
, host
=controller_ip
,
1434 password
=self
.config
.get('ovs_controller_password'),
1435 keyfile
=self
.config
.get('ovs_controller_keyfile'),
1436 db
=self
.config
["db"], test
=host_test_mode
,
1437 image_path
=self
.config
['host_image_path'], version
=self
.config
['version'],
1438 host_id
='openvim_controller', develop_mode
=host_develop_mode
,
1439 develop_bridge_iface
=bridge_ifaces
,
1440 logger_name
=self
.logger_name
+ ".host.controller",
1441 debug
=self
.config
.get('log_level_host'))
1443 self
.config
['host_threads']['openvim_controller'] = dhcp_host
1445 dhcp_host
.check_connectivity()
1446 except Exception as e
:
1451 def launch_dhcp_server(self
, vlan
, first_ip
, last_ip
, cidr
, gateway
, dns
, routes
):
1453 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1454 :param vlan: vlan identifier
1455 :param first_ip: First dhcp range ip
1456 :param last_ip: Last dhcp range ip
1457 :param cidr: net cidr
1458 :param gateway: net gateway
1461 ip_tools
= IPNetwork(cidr
)
1462 dhcp_netmask
= str(ip_tools
.netmask
)
1463 ip_range
= [first_ip
, last_ip
]
1465 dhcp_path
= self
.config
['ovs_controller_file_path']
1467 controller_host
= self
.get_dhcp_controller()
1469 # controller_host.create_linux_bridge(vlan)
1470 controller_host
.create_dhcp_interfaces(vlan
, first_ip
, dhcp_netmask
)
1471 dhcp_path
= self
.config
['ovs_controller_file_path']
1472 controller_host
.launch_dhcp_server(vlan
, ip_range
, dhcp_netmask
, dhcp_path
, gateway
, dns
, routes
)
1474 def launch_link_bridge_to_ovs(self
, vlan
, gateway
, dhcp_cidr
, links
=None, routes
=None):
1476 Launch creating of connections (veth) between user bridge (link) and OVS
1484 controller_host
= self
.get_dhcp_controller()
1486 if 'iface' in link
and 'nat' not in link
:
1487 controller_host
.create_link_bridge_to_ovs(vlan
, link
['iface'])
1489 controller_host
.create_qrouter_ovs_connection(vlan
, gateway
, dhcp_cidr
)
1490 controller_host
.create_qrouter_br_connection(vlan
, dhcp_cidr
, link
)
1493 controller_host
.add_ns_routes(vlan
, routes
)
1495 def delete_link_bridge_to_ovs(self
, vlan
, links
=None):
1497 Delete connections (veth) between user bridge (link) and OVS
1503 controller_host
= self
.get_dhcp_controller()
1506 if 'iface' in link
and 'nat' not in link
:
1507 controller_host
.remove_link_bridge_to_ovs(vlan
, link
['iface'])
1509 controller_host
.delete_qrouter_connection(vlan
, link
['iface'])
1512 if __name__
== "__main__":
1514 parser
= argparse
.ArgumentParser()
1515 parser
.add_argument("-v","--version", help="show ovim library version", action
="store_true")
1516 parser
.add_argument("--database-version", help="show required database version", action
="store_true")
1517 args
= parser
.parse_args()
1519 print ('openvimd version {} {}'.format(ovim
.get_version(), ovim
.get_version_date()))
1520 print ('(c) Copyright Telefonica')
1521 elif args
.database_version
:
1522 print ('required database version: {}'.format(ovim
.get_database_version()))