2 # -*- coding: utf-8 -*-
5 # Copyright 2015 Telefónica Investigación 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.28-r548"
47 version_date
= "Jul 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
()
192 self
.config
["db_lock"] = threading
.Lock()
194 self
.of_test_mode
= False if self
.config
['mode'] == 'normal' or self
.config
['mode'] == "OF only" else True
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)
201 # get host list from data base before starting threads
202 r
, hosts
= self
.db
.get_table(SELECT
=('name', 'ip_name', 'user', 'uuid', 'hypervisors', 'password', 'keyfile'),
203 FROM
='hosts', WHERE
={'status': 'ok'}) #Unikernels extension
205 raise ovimException("Cannot get hosts from database {}".format(hosts
))
207 self
.config
['host_threads'] = {}
210 thread
= ht
.host_thread(name
=host
['name'], user
=host
['user'], host
=host
['ip_name'], db
=self
.config
["db"],
211 password
=host
['password'],
212 keyfile
=host
.get('keyfile', self
.config
["host_ssh_keyfile"]),
213 db_lock
=self
.config
["db_lock"], test
=host_test_mode
,
214 image_path
=self
.config
['host_image_path'],
215 version
=self
.config
['version'], host_id
=host
['uuid'],
216 develop_mode
=host_develop_mode
,
217 develop_bridge_iface
=host_develop_bridge_iface
,
218 hypervisors
=host
['hypervisors'], #Unikernels extension
219 logger_name
=self
.logger_name
+ ".host." + host
['name'],
220 debug
=self
.config
.get('log_level_host'))
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']))
228 self
.config
['host_threads'][host
['uuid']] = thread
230 # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge,
233 self
.config
['dhcp_nets'] = []
234 self
.config
['bridge_nets'] = []
235 for bridge
, vlan_speed
in self
.config
["bridge_ifaces"].items():
236 # skip 'development_bridge'
237 if self
.config
['mode'] == 'development' and self
.config
['development_bridge'] == bridge
:
239 self
.config
['bridge_nets'].append([bridge
, vlan_speed
[0], vlan_speed
[1], None])
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']:
244 r
, nets
= self
.db
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'provider': "bridge:" + brnet
[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", ()):
256 r
, nets
= self
.db
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'name': net
})
258 self
.config
['dhcp_nets'].append(nets
[0]['uuid'])
261 self
._start
_ofc
_default
_task
()
263 # OFC per tenant in DB
264 self
._start
_of
_db
_tasks
()
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")
270 thread
= dt
.dhcp_thread(dhcp_params
=dhcp_params
, test
=host_test_mode
, dhcp_nets
=self
.config
["dhcp_nets"],
271 db
=self
.config
["db"], db_lock
=self
.config
["db_lock"],
272 logger_name
=self
.logger_name
+ ".dhcp",
273 debug
=self
.config
.get('log_level_of'))
275 self
.config
['dhcp_thread'] = thread
279 # create ovs dhcp thread
280 result
, content
= self
.db
.get_table(FROM
='nets')
282 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
283 raise ovimException(str(content
), -result
)
286 net_type
= net
['type']
287 if net
['status'] != "INACTIVE" and (net_type
== 'bridge_data' or net_type
== 'bridge_man') and \
288 net
["provider"][:4] == 'OVS:' and net
["enable_dhcp"] == "true":
290 config_routes
= net
.get('routes')
292 routes
= yaml
.safe_load(config_routes
)
296 config_dns
= net
.get('dns')
298 dns
= yaml
.safe_load(config_dns
)
302 links
= net
.get('links')
304 links
= yaml
.safe_load(net
.get('links'))
305 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'),
310 net
.get('gateway_ip'),
313 self
.launch_link_bridge_to_ovs(net
['vlan'], net
.get('gateway_ip'), net
.get('cidr'), links
, routes
)
314 if net
["status"] == "ERROR":
315 self
.db
.update_rows("nets", UPDATE
={"status": "ACTIVE", "last_error": None},
316 WHERE
={"uuid": net
["uuid"]})
317 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
))
320 self
.db
.update_rows("nets", UPDATE
={"status": "ERROR",
321 "last_error": "Fail at launching dhcp server: " + str(e
)},
322 WHERE
={"uuid": net
["uuid"]})
324 def _start_of_db_tasks(self
):
326 Start ofc task for existing ofcs in database
331 ofcs
= self
.get_of_controllers()
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
)
338 def _create_ofc_task(self
, ofc_uuid
, dpid
, of_conn
):
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
346 if 'ofcs_thread' not in self
.config
and 'ofcs_thread_dpid' not in self
.config
:
348 ofcs_thread_dpid
= []
350 ofcs_threads
= self
.config
['ofcs_thread']
351 ofcs_thread_dpid
= self
.config
['ofcs_thread_dpid']
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
358 ofcs_threads
[ofc_uuid
] = ofc_thread
359 self
.config
['ofcs_thread'] = ofcs_threads
361 ofcs_thread_dpid
.append({dpid
: ofc_thread
})
362 self
.config
['ofcs_thread_dpid'] = ofcs_thread_dpid
364 def _start_ofc_default_task(self
):
366 Create default ofc thread
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
:
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')
383 # create connector to the openflow controller
384 # load other parameters starting by of_ from config dict in a temporal dict
386 of_conn
= self
._load
_of
_module
(db_config
)
387 # create openflow thread
388 self
._create
_ofc
_task
("Default", db_config
['dpid'], of_conn
)
390 def _load_of_module(self
, db_config
):
392 import python module for each SDN controller supported
393 :param db_config: SDN dn information
397 raise ovimException("No module found it", HTTP_Internal_Server_Error
)
402 if self
.of_test_mode
:
403 return openflow_conn
.OfTestConnector({"name": db_config
['type'],
404 "dpid": db_config
['dpid'],
405 "of_debug": self
.config
['log_level_of']})
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']
413 temp_dict
['of_user'] = db_config
.get('user')
414 temp_dict
['of_password'] = db_config
.get('password')
416 temp_dict
['of_debug'] = self
.config
['log_level_of']
418 if temp_dict
['of_controller'] == 'opendaylight':
421 module
= temp_dict
['of_controller']
423 if module
not in ovim
.of_module
:
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
:
430 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
)
435 of_conn_module
= ovim
.of_module
[module
]
436 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
)),
440 HTTP_Internal_Server_Error
)
442 def _create_ofc_thread(self
, of_conn
, ofc_uuid
="Default"):
444 Create and launch a of thread
447 # create openflow thread
449 #if 'of_controller_nets_with_same_vlan' in self.config:
450 # ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
452 # ofc_net_same_vlan = False
453 ofc_net_same_vlan
= False
455 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'))
460 #r, c = thread.OF_connector.obtain_port_correspondence()
462 # raise ovimException("Cannot get openflow information %s", c)
466 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'])
470 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
]
475 if 'dhcp_thread' in self
.config
:
476 threads
['dhcp'] = (self
.config
['dhcp_thread'])
478 for thread_id
, thread
in threads
.items():
479 if thread_id
== 'openvim_controller':
481 thread
.insert_task("exit")
482 for thread_id
, thread
in threads
.items():
483 if thread_id
== 'openvim_controller':
487 def get_networks(self
, columns
=None, db_filter
={}, limit
=None):
489 Retreive networks available
490 :param columns: List with select query parameters
491 :param db_filter: List with where query parameters
492 :param limit: Query limit result
495 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='nets', WHERE
=db_filter
, LIMIT
=limit
)
498 raise ovimException(str(content
), -result
)
500 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
504 def show_network(self
, network_id
, db_filter
={}, skip_on_not_found
=False):
506 Get network from DB by id
507 :param network_id: net Id
508 :param db_filter: List with where query parameters
513 raise ovimException("Not network id was not found")
514 db_filter
['uuid'] = network_id
516 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
=db_filter
, LIMIT
=100)
519 raise ovimException(str(content
), -result
)
521 if skip_on_not_found
:
523 raise ovimException("show_network network '%s' not found" % network_id
, HTTP_Not_Found
)
525 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
527 result
, ports
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
528 WHERE
={'net_id': network_id
}, LIMIT
=100)
530 content
[0]['ports'] = ports
531 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
533 result
, flows
= self
.db
.get_table(FROM
='of_flows', SELECT
=('priority', 'vlan_id', 'ingress_port', 'src_mac', 'dst_mac', 'actions'),
534 WHERE
={'net_id': network_id
}, LIMIT
=100)
536 content
[0]['flows'] = flows
539 def new_network(self
, network
):
544 tenant_id
= network
.get('tenant_id')
547 result
, _
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
, "enabled": True})
549 raise ovimException("set_network error, no tenant founded", -result
)
553 net_provider
= network
.get('provider')
554 net_type
= network
.get('type')
555 net_vlan
= network
.get("vlan")
556 net_bind_net
= network
.get("bind_net")
557 net_bind_type
= network
.get("bind_type")
558 net_region
= network
.get("region")
559 name
= network
["name"]
561 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
562 vlan_index
= name
.rfind(":")
563 if not net_bind_net
and not net_bind_type
and vlan_index
> 1:
565 vlan_tag
= int(name
[vlan_index
+ 1:])
566 if not vlan_tag
and vlan_tag
< 4096:
567 net_bind_net
= name
[:vlan_index
]
568 net_bind_type
= "vlan:" + name
[vlan_index
+ 1:]
573 # look for a valid net
574 if self
._check
_valid
_uuid
(net_bind_net
):
575 net_bind_key
= "uuid"
577 net_bind_key
= "name"
578 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
580 raise ovimException(' getting nets from db ' + content
, HTTP_Internal_Server_Error
)
582 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
584 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
585 network
["bind_net"] = content
[0]["uuid"]
588 if net_bind_type
[0:5] != "vlan:":
589 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
590 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
591 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
593 network
["bind_type"] = net_bind_type
596 if net_provider
[:9] == "openflow:":
598 if net_type
!= "ptp" and net_type
!= "data":
599 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
605 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
606 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
607 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
609 net_type
= 'bridge_man'
612 net_type
= 'bridge_man'
615 if net_provider
[:7] == 'bridge:':
616 # check it is one of the pre-provisioned bridges
617 bridge_net_name
= net_provider
[7:]
618 for brnet
in self
.config
['bridge_nets']:
619 if brnet
[0] == bridge_net_name
: # free
621 raise ovimException("invalid 'provider:physical', "
622 "bridge '%s' is already used" % bridge_net_name
, HTTP_Conflict
)
626 # if bridge_net==None:
627 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
628 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
631 elif self
.config
['network_type'] == 'bridge' and (net_type
== 'bridge_data' or net_type
== 'bridge_man'):
632 # look for a free precreated nets
633 for brnet
in self
.config
['bridge_nets']:
634 if not brnet
[3]: # free
636 if net_type
== 'bridge_man': # look for the smaller speed
637 if brnet
[2] < bridge_net
[2]:
639 else: # look for the larger speed
640 if brnet
[2] > bridge_net
[2]:
646 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
647 "will overcome this limit", HTTP_Bad_Request
)
649 self
.logger
.debug("using net " + bridge_net
)
650 net_provider
= "bridge:" + bridge_net
[0]
651 net_vlan
= bridge_net
[1]
652 elif net_type
== 'bridge_data' or net_type
== 'bridge_man' and self
.config
['network_type'] == 'ovs':
655 if net_type
== "data" or net_type
== "ptp":
656 net_region
= "__DATA__"
657 elif net_provider
== "OVS":
658 net_region
= "__OVS__"
659 if not net_vlan
and (net_type
== "data" or net_type
== "ptp" or net_provider
== "OVS"):
660 net_vlan
= self
.db
.get_free_net_vlan(net_region
)
662 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error
)
663 if net_provider
== 'OVS':
664 net_provider
= 'OVS' + ":" + str(net_vlan
)
666 network
['provider'] = net_provider
667 network
['type'] = net_type
668 network
['vlan'] = net_vlan
669 network
['region'] = net_region
670 dhcp_integrity
= True
671 if network
.get('enable_dhcp'):
672 dhcp_integrity
= self
._check
_dhcp
_data
_integrity
(network
)
674 if network
.get('links'):
675 network
['links'] = yaml
.safe_dump(network
['links'], default_flow_style
=True, width
=256)
676 if network
.get('dns'):
677 network
['dns'] = yaml
.safe_dump(network
['dns'], default_flow_style
=True, width
=256)
678 if network
.get('routes'):
679 network
['routes'] = yaml
.safe_dump(network
['routes'], default_flow_style
=True, width
=256)
681 result
, content
= self
.db
.new_row('nets', network
, True, True)
682 if result
>= 0: # and dhcp_integrity:
684 bridge_net
[3] = content
685 if self
.config
.get("dhcp_server") and self
.config
['network_type'] == 'bridge':
686 if network
["name"] in self
.config
["dhcp_server"].get("nets", ()):
687 self
.config
["dhcp_nets"].append(content
)
688 self
.logger
.debug("dhcp_server: add new net", content
)
689 elif bridge_net
and bridge_net
[0] in self
.config
["dhcp_server"].get("bridge_ifaces", ()):
690 self
.config
["dhcp_nets"].append(content
)
691 self
.logger
.debug("dhcp_server: add new net", content
, content
)
694 raise ovimException("Error creating network: {}".format(content
), -result
)
696 # TODO kei change update->edit
698 def edit_network(self
, network_id
, network
):
700 Update entwork data byt id
703 # Look for the previous data
704 where_
= {'uuid': network_id
}
705 result
, network_old
= self
.db
.get_table(FROM
='nets', WHERE
=where_
)
707 raise ovimException("Error updating network %s" % network_old
, HTTP_Internal_Server_Error
)
709 raise ovimException('network %s not found' % network_id
, HTTP_Not_Found
)
711 nbports
, content
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
712 WHERE
={'net_id': network_id
}, LIMIT
=100)
714 raise ovimException("http_put_network_id error %d %s" % (result
, network_old
), HTTP_Internal_Server_Error
)
716 if 'type' in network
and network
['type'] != network_old
[0]['type']:
717 raise ovimException("Can not change type of network while having ports attached",
718 HTTP_Method_Not_Allowed
)
719 if 'vlan' in network
and network
['vlan'] != network_old
[0]['vlan']:
720 raise ovimException("Can not change vlan of network while having ports attached",
721 HTTP_Method_Not_Allowed
)
724 net_provider
= network
.get('provider', network_old
[0]['provider'])
725 net_type
= network
.get('type', network_old
[0]['type'])
726 net_bind_net
= network
.get("bind_net")
727 net_bind_type
= network
.get("bind_type")
729 # look for a valid net
730 if self
._check
_valid
_uuid
(net_bind_net
):
731 net_bind_key
= "uuid"
733 net_bind_key
= "name"
734 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
736 raise ovimException('Getting nets from db ' + content
, HTTP_Internal_Server_Error
)
738 raise ovimException("bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
740 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
),
742 network
["bind_net"] = content
[0]["uuid"]
744 if net_bind_type
[0:5] != "vlan:":
745 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
746 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
747 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
750 if net_provider
[:9] == "openflow:":
751 if net_type
!= "ptp" and net_type
!= "data":
752 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request
)
754 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
755 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
756 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
758 # insert in data base
759 result
, content
= self
.db
.update_rows('nets', network
, WHERE
={'uuid': network_id
}, log
=True)
761 # if result > 0 and nbports>0 and 'admin_state_up' in network
762 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
767 self
.net_update_ofc_thread(network_id
)
768 except ovimException
as e
:
769 raise ovimException("Error while launching openflow rules in network '{}' {}"
770 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
771 except Exception as e
:
772 raise ovimException("Error while launching openflow rules in network '{}' {}"
773 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
775 if self
.config
.get("dhcp_server"):
776 if network_id
in self
.config
["dhcp_nets"]:
777 self
.config
["dhcp_nets"].remove(network_id
)
778 if network
.get("name", network_old
[0]["name"]) in self
.config
["dhcp_server"].get("nets", ()):
779 self
.config
["dhcp_nets"].append(network_id
)
781 net_bind
= network
.get("bind_type", network_old
[0]["bind_type"])
782 if net_bind
and net_bind
and net_bind
[:7] == "bridge:" and net_bind
[7:] in self
.config
["dhcp_server"].get(
783 "bridge_ifaces", ()):
784 self
.config
["dhcp_nets"].append(network_id
)
787 raise ovimException(content
, -result
)
789 def delete_network(self
, network_id
, idempotent
=True):
791 Delete network by network id
792 :param network_id: network id
795 net_data
= self
.show_network(network_id
, skip_on_not_found
=idempotent
)
796 if not net_data
: # network does not exist
799 # delete from the data base
800 result
, content
= self
.db
.delete_row('nets', network_id
)
803 raise ovimException("Network %s not found " % network_id
, HTTP_Not_Found
)
805 for brnet
in self
.config
['bridge_nets']:
806 if brnet
[3] == network_id
:
809 if self
.config
.get("dhcp_server") and network_id
in self
.config
["dhcp_nets"]:
810 self
.config
["dhcp_nets"].remove(network_id
)
812 if net_data
.get('enable_dhcp'):
813 dhcp_path
= self
.config
['ovs_controller_file_path']
814 dhcp_controller
= self
.get_dhcp_controller()
815 dhcp_controller
.delete_dhcp_server(net_data
['vlan'], network_id
, dhcp_path
)
816 dhcp_controller
.delete_dhcp_port(net_data
['vlan'], network_id
, dhcp_path
)
817 links
= yaml
.load(net_data
.get('links'))
819 links
= yaml
.load(net_data
.get('links'))
820 self
.delete_link_bridge_to_ovs(net_data
['vlan'], links
)
824 raise ovimException("Error deleting network '{}': {}".format(network_id
, content
), -result
)
826 def get_openflow_rules(self
, network_id
=None):
828 Get openflow id from DB
829 :param network_id: Network id, if none all networks will be retrieved
830 :return: Return a list with Openflow rules per net
836 where_
= {"net_id": network_id
}
837 result
, content
= self
.db
.get_table(
838 SELECT
=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
839 WHERE
=where_
, FROM
='of_flows')
842 raise ovimException(str(content
), -result
)
845 def edit_openflow_rules(self
, network_id
=None):
848 To make actions over the net. The action is to reinstall the openflow rules
849 network_id can be 'all'
850 :param network_id: Network id, if none all networks will be retrieved
851 :return : Number of nets updated
858 where_
= {"uuid": network_id
}
859 result
, content
= self
.db
.get_table(SELECT
=("uuid", "type"), WHERE
=where_
, FROM
='nets')
862 raise ovimException(str(content
), -result
)
865 if net
["type"] != "ptp" and net
["type"] != "data":
870 self
.net_update_ofc_thread(net
['uuid'])
871 except ovimException
as e
:
872 raise ovimException("Error updating network'{}' {}".format(net
['uuid'], str(e
)),
873 HTTP_Internal_Server_Error
)
874 except Exception as e
:
875 raise ovimException("Error updating network '{}' {}".format(net
['uuid'], str(e
)),
876 HTTP_Internal_Server_Error
)
880 def delete_openflow_rules(self
, ofc_id
=None):
882 To make actions over the net. The action is to delete ALL openflow rules
883 :return: return operation result
887 if 'Default' in self
.config
['ofcs_thread']:
888 r
, c
= self
.config
['ofcs_thread']['Default'].insert_task("clear-all")
890 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
892 elif ofc_id
in self
.config
['ofcs_thread']:
893 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("clear-all")
897 raise ovimException(str(c
), -r
)
899 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
902 def get_openflow_ports(self
, ofc_id
=None):
904 Obtain switch ports names of openflow controller
905 :return: Return flow ports in DB
908 if 'Default' in self
.config
['ofcs_thread']:
909 conn
= self
.config
['ofcs_thread']['Default'].OF_connector
911 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
913 elif ofc_id
in self
.config
['ofcs_thread']:
914 conn
= self
.config
['ofcs_thread'][ofc_id
].OF_connector
916 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
919 def get_ports(self
, columns
=None, filter={}, limit
=None):
920 # result, content = my.db.get_ports(where_)
921 result
, content
= self
.db
.get_table(SELECT
=columns
, WHERE
=filter, FROM
='ports', LIMIT
=limit
)
923 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
924 raise ovimException(str(content
), -result
)
926 convert_boolean(content
, ('admin_state_up',))
929 def new_port(self
, port_data
):
930 port_data
['type'] = 'external'
931 if port_data
.get('net_id'):
932 # check that new net has the correct type
933 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
935 raise ovimException(str(new_net
), -result
)
936 # insert in data base
937 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
939 if 'net_id' in port_data
:
941 self
.net_update_ofc_thread(port_data
['net_id'])
942 except ovimException
as e
:
943 raise ovimException("Cannot insert a task for updating network '{}' {}"
944 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
945 except Exception as e
:
946 raise ovimException("Cannot insert a task for updating network '{}' {}"
947 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
951 raise ovimException(str(uuid
), -result
)
953 def new_external_port(self
, port_data
):
955 Create new external port and check port mapping correspondence
956 :param port_data: port_data = {
957 'region': 'datacenter region',
958 'compute_node': 'compute node id',
959 'pci': 'pci port address',
962 'tenant_id': 'tenant id',
965 'ip_address': 'ip address - optional'}
969 port_data
['type'] = 'external'
971 if port_data
.get('net_id'):
972 # check that new net has the correct type
973 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
975 raise ovimException(str(new_net
), -result
)
976 # insert in data base
979 if port_data
.get('region'):
980 db_filter
['region'] = port_data
['region']
981 if port_data
.get('pci'):
982 db_filter
['pci'] = port_data
['pci']
983 if port_data
.get('compute_node'):
984 db_filter
['compute_node'] = port_data
['compute_node']
986 columns
= ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
987 port_mapping_data
= self
.get_of_port_mappings(columns
, db_filter
)
989 if not len(port_mapping_data
):
990 raise ovimException("No port mapping founded for '{}'".format(str(db_filter
)),
992 elif len(port_mapping_data
) > 1:
993 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
996 port_data
['ofc_id'] = port_mapping_data
[0]['ofc_id']
997 port_data
['switch_dpid'] = port_mapping_data
[0]['switch_dpid']
998 port_data
['switch_port'] = port_mapping_data
[0]['switch_port']
999 port_data
['switch_mac'] = port_mapping_data
[0]['switch_mac']
1001 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
1002 if 'region' in port_data
:
1003 del port_data
['region']
1004 if 'pci' in port_data
:
1005 del port_data
['pci']
1006 if 'compute_node' in port_data
:
1007 del port_data
['compute_node']
1009 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
1010 # set net status to BUILD
1011 self
.db
.update_rows('nets', {"status": "BUILD"}, WHERE
={'uuid': port_data
['net_id']})
1014 self
.net_update_ofc_thread(port_data
['net_id'], port_data
['ofc_id'])
1015 except ovimException
as e
:
1016 raise ovimException("Cannot insert a task for updating network '{}' {}".
1017 format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
1018 except Exception as e
:
1019 raise ovimException("Cannot insert a task for updating network '{}' {}"
1020 .format(port_data
['net_id'], e
), HTTP_Internal_Server_Error
)
1023 raise ovimException(str(uuid
), -result
)
1025 def net_update_ofc_thread(self
, net_id
, ofc_id
=None, switch_dpid
=None):
1027 Insert a update net task by net id or ofc_id for each ofc thread
1028 :param net_id: network id
1029 :param ofc_id: openflow controller id
1030 :param switch_dpid: switch dpid
1034 raise ovimException("No net_id received", HTTP_Internal_Server_Error
)
1037 c
= 'No valid ofc_id or switch_dpid received'
1040 ports
= self
.get_ports(filter={"net_id": net_id
})
1042 port_ofc_id
= port
.get('ofc_id', None)
1044 ofc_id
= port
['ofc_id']
1045 switch_dpid
= port
['switch_dpid']
1047 #TODO if not ofc_id: look at database table ofcs
1050 # If no ofc_id found it, default ofc_id is used.
1051 if not ofc_id
and not switch_dpid
:
1054 if ofc_id
and ofc_id
in self
.config
['ofcs_thread']:
1055 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("update-net", net_id
)
1058 ofcs_dpid_list
= self
.config
['ofcs_thread_dpid']
1059 for ofc_t
in ofcs_dpid_list
:
1060 if switch_dpid
in ofc_t
:
1061 r
, c
= ofc_t
[switch_dpid
].insert_task("update-net", net_id
)
1064 message
= "Cannot insert a task for updating network '{}', {}".format(net_id
, c
)
1065 self
.logger
.error(message
)
1066 raise ovimException(message
, HTTP_Internal_Server_Error
)
1068 def delete_port(self
, port_id
, idempotent
=False):
1069 # Look for the previous port data
1070 result
, ports
= self
.db
.get_table(WHERE
={'uuid': port_id
, "type": "external"}, FROM
='ports')
1072 raise ovimException("Cannot get port info from database: {}".format(ports
), http_code
=-result
)
1073 # delete from the data base
1074 result
, content
= self
.db
.delete_row('ports', port_id
)
1078 raise ovimException("External port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1080 raise ovimException("Cannot delete port from database: {}".format(content
), http_code
=-result
)
1082 net_id
= ports
[0].get('net_id', None)
1086 # set net status to BUILD
1087 self
.db
.update_rows('nets', {"status": "BUILD"}, WHERE
={'uuid': net_id
})
1089 self
.net_update_ofc_thread(net_id
, ofc_id
=ports
[0]["ofc_id"], switch_dpid
=ports
[0]["switch_dpid"])
1090 except ovimException
as e
:
1091 raise ovimException("Cannot insert a task for delete network '{}' {}".format(net_id
, str(e
)),
1092 HTTP_Internal_Server_Error
)
1093 except Exception as e
:
1094 raise ovimException("Cannot insert a task for delete network '{}' {}".format(net_id
, str(e
)),
1095 HTTP_Internal_Server_Error
)
1099 def edit_port(self
, port_id
, port_data
, admin
=True):
1100 # Look for the previous port data
1101 result
, content
= self
.db
.get_table(FROM
="ports", WHERE
={'uuid': port_id
})
1103 raise ovimException("Cannot get port info from database: {}".format(content
), http_code
=-result
)
1105 raise ovimException("Port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1110 if 'net_id' in port_data
:
1112 old_net
= port
.get('net_id', None)
1113 new_net
= port_data
['net_id']
1114 if old_net
!= new_net
:
1117 nets
.append(new_net
) # put first the new net, so that new openflow rules are created before removing the old ones
1119 nets
.append(old_net
)
1120 if port
['type'] == 'instance:bridge' or port
['type'] == 'instance:ovs':
1121 raise ovimException("bridge interfaces cannot be attached to a different net", http_code
=HTTP_Forbidden
)
1122 elif port
['type'] == 'external' and not admin
:
1123 raise ovimException("Needed admin privileges",http_code
=HTTP_Unauthorized
)
1125 # check that new net has the correct type
1126 result
, new_net_dict
= self
.db
.check_target_net(new_net
, None, port
['type'])
1128 raise ovimException("Error {}".format(new_net_dict
), http_code
=HTTP_Conflict
)
1129 # change VLAN for SR-IOV ports
1130 if result
>= 0 and port
["type"] == "instance:data" and port
["model"] == "VF": # TODO consider also VFnotShared
1132 port_data
["vlan"] = None
1134 port_data
["vlan"] = new_net_dict
["vlan"]
1135 # get host where this VM is allocated
1136 result
, content
= self
.db
.get_table(FROM
="instances", WHERE
={"uuid": port
["instance_id"]})
1138 host_id
= content
[0]["host_id"]
1140 # insert in data base
1142 result
, content
= self
.db
.update_rows('ports', port_data
, WHERE
={'uuid': port_id
}, log
=False)
1143 port
.update(port_data
)
1145 # Insert task to complete actions
1149 self
.net_update_ofc_thread(net_id
, port
["ofc_id"], switch_dpid
=port
["switch_dpid"])
1150 except ovimException
as e
:
1151 raise ovimException("Error updating network'{}' {}".format(net_id
, str(e
)),
1152 HTTP_Internal_Server_Error
)
1153 except Exception as e
:
1154 raise ovimException("Error updating network '{}' {}".format(net_id
, str(e
)),
1155 HTTP_Internal_Server_Error
)
1158 r
, v
= self
.config
['host_threads'][host_id
].insert_task("edit-iface", port_id
, old_net
, new_net
)
1160 self
.logger
.error("Error updating network '{}' {}".format(r
,v
))
1161 # TODO Do something if fails
1165 raise ovimException("Error {}".format(content
), http_code
=-result
)
1167 def new_of_controller(self
, ofc_data
):
1169 Create a new openflow controller into DB
1170 :param ofc_data: Dict openflow controller data
1171 :return: openflow controller dpid
1174 result
, ofc_uuid
= self
.db
.new_row('ofcs', ofc_data
, True, True)
1176 raise ovimException("New ofc Error %s" % ofc_uuid
, HTTP_Internal_Server_Error
)
1178 ofc_data
['uuid'] = ofc_uuid
1179 of_conn
= self
._load
_of
_module
(ofc_data
)
1180 self
._create
_ofc
_task
(ofc_uuid
, ofc_data
['dpid'], of_conn
)
1184 def edit_of_controller(self
, of_id
, ofc_data
):
1186 Edit an openflow controller entry from DB
1190 raise ovimException("No data received during uptade OF contorller", http_code
=HTTP_Internal_Server_Error
)
1192 old_of_controller
= self
.show_of_controller(of_id
)
1194 if old_of_controller
:
1195 result
, content
= self
.db
.update_rows('ofcs', ofc_data
, WHERE
={'uuid': of_id
}, log
=False)
1199 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1202 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1203 http_code
=HTTP_Internal_Server_Error
)
1205 def delete_of_controller(self
, of_id
):
1207 Delete an openflow controller from DB.
1208 :param of_id: openflow controller dpid
1212 ofc
= self
.show_of_controller(of_id
)
1214 result
, content
= self
.db
.delete_row("ofcs", of_id
)
1216 raise ovimException("Cannot delete ofc from database: {}".format(content
), http_code
=-result
)
1218 raise ovimException("ofc {} not found ".format(content
), http_code
=HTTP_Not_Found
)
1220 ofc_thread
= self
.config
['ofcs_thread'][of_id
]
1221 del self
.config
['ofcs_thread'][of_id
]
1222 for ofc_th
in self
.config
['ofcs_thread_dpid']:
1223 if ofc
['dpid'] in ofc_th
:
1224 self
.config
['ofcs_thread_dpid'].remove(ofc_th
)
1226 ofc_thread
.insert_task("exit")
1231 def show_of_controller(self
, uuid
):
1233 Show an openflow controller by dpid from DB.
1234 :param db_filter: List with where query parameters
1238 result
, content
= self
.db
.get_table(FROM
='ofcs', WHERE
={"uuid": uuid
}, LIMIT
=100)
1241 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid
),
1242 http_code
=HTTP_Not_Found
)
1244 raise ovimException("Openflow controller with uuid '{}' error".format(uuid
),
1245 http_code
=HTTP_Internal_Server_Error
)
1248 def get_of_controllers(self
, columns
=None, db_filter
={}, limit
=None):
1250 Show an openflow controllers from DB.
1251 :param columns: List with SELECT query parameters
1252 :param db_filter: List with where query parameters
1253 :param limit: result Limit
1256 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='ofcs', WHERE
=db_filter
, LIMIT
=limit
)
1259 raise ovimException(str(content
), -result
)
1263 def get_tenants(self
, columns
=None, db_filter
={}, limit
=None):
1265 Retrieve tenant list from DB
1266 :param columns: List with SELECT query parameters
1267 :param db_filter: List with where query parameters
1268 :param limit: result limit
1271 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=columns
, WHERE
=db_filter
, LIMIT
=limit
)
1273 raise ovimException('get_tenatns Error {}'.format(str(content
)), -result
)
1275 convert_boolean(content
, ('enabled',))
1278 def show_tenant_id(self
, tenant_id
):
1280 Get tenant from DB by id
1281 :param tenant_id: tenant id
1284 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid', 'name', 'description', 'enabled'),
1285 WHERE
={"uuid": tenant_id
})
1287 raise ovimException(str(content
), -result
)
1289 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1291 convert_boolean(content
, ('enabled',))
1294 def new_tentant(self
, tenant
):
1296 Create a tenant and store in DB
1297 :param tenant: Dictionary with tenant data
1298 :return: the uuid of created tenant. Raise exception upon error
1301 # insert in data base
1302 result
, tenant_uuid
= self
.db
.new_tenant(tenant
)
1307 raise ovimException(str(tenant_uuid
), -result
)
1309 def delete_tentant(self
, tenant_id
):
1311 Delete a tenant from the database.
1312 :param tenant_id: Tenant id
1313 :return: delete tenant id
1317 r
, tenants_flavors
= self
.db
.get_table(FROM
='tenants_flavors', SELECT
=('flavor_id', 'tenant_id'),
1318 WHERE
={'tenant_id': tenant_id
})
1320 tenants_flavors
= ()
1321 r
, tenants_images
= self
.db
.get_table(FROM
='tenants_images', SELECT
=('image_id', 'tenant_id'),
1322 WHERE
={'tenant_id': tenant_id
})
1326 result
, content
= self
.db
.delete_row('tenants', tenant_id
)
1328 raise ovimException("tenant '%s' not found" % tenant_id
, HTTP_Not_Found
)
1330 for flavor
in tenants_flavors
:
1331 self
.db
.delete_row_by_key("flavors", "uuid", flavor
['flavor_id'])
1332 for image
in tenants_images
:
1333 self
.db
.delete_row_by_key("images", "uuid", image
['image_id'])
1336 raise ovimException("Error deleting tenant '%s' " % tenant_id
, HTTP_Internal_Server_Error
)
1338 def edit_tenant(self
, tenant_id
, tenant_data
):
1340 Update a tenant data identified by tenant id
1341 :param tenant_id: tenant id
1342 :param tenant_data: Dictionary with tenant data
1346 # Look for the previous data
1347 result
, tenant_data_old
= self
.db
.get_table(FROM
='tenants', WHERE
={'uuid': tenant_id
})
1349 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id
, tenant_data_old
),
1350 HTTP_Internal_Server_Error
)
1352 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1354 # insert in data base
1355 result
, content
= self
.db
.update_rows('tenants', tenant_data
, WHERE
={'uuid': tenant_id
}, log
=True)
1359 raise ovimException(str(content
), -result
)
1361 def set_of_port_mapping(self
, of_maps
, ofc_id
=None, switch_dpid
=None, region
=None):
1363 Create new port mapping entry
1364 :param of_maps: List with port mapping information
1365 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1366 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1367 :param ofc_id: ofc id
1368 :param switch_dpid: switch dpid
1369 :param region: datacenter region id
1375 map['ofc_id'] = ofc_id
1377 map['switch_dpid'] = switch_dpid
1379 map['region'] = region
1381 map["pci"] = map["pci"].lower()
1383 for of_map
in of_maps
:
1384 result
, uuid
= self
.db
.new_row('of_port_mappings', of_map
, True)
1386 of_map
["uuid"] = uuid
1388 raise ovimException(str(uuid
), -result
)
1391 def clear_of_port_mapping(self
, db_filter
={}):
1393 Clear port mapping filtering using db_filter dict
1394 :param db_filter: Parameter to filter during remove process
1397 result
, content
= self
.db
.delete_row_by_dict(FROM
='of_port_mappings', WHERE
=db_filter
)
1402 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter
)),
1403 HTTP_Internal_Server_Error
)
1405 def get_of_port_mappings(self
, column
=None, db_filter
=None, db_limit
=None):
1407 Retrive port mapping from DB
1412 result
, content
= self
.db
.get_table(SELECT
=column
, WHERE
=db_filter
, FROM
='of_port_mappings', LIMIT
=db_limit
)
1415 self
.logger
.error("get_of_port_mappings Error %d %s", result
, content
)
1416 raise ovimException(str(content
), -result
)
1420 def get_dhcp_controller(self
):
1422 Create an host_thread object for manage openvim controller and not create a thread for itself
1423 :return: dhcp_host openvim controller object
1426 if 'openvim_controller' in self
.config
['host_threads']:
1427 return self
.config
['host_threads']['openvim_controller']
1430 controller_ip
= self
.config
['ovs_controller_ip']
1431 ovs_controller_user
= self
.config
.get('ovs_controller_user')
1433 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
1434 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
1436 dhcp_host
= ht
.host_thread(name
='openvim_controller', user
=ovs_controller_user
, host
=controller_ip
,
1437 password
=self
.config
.get('ovs_controller_password'),
1438 keyfile
=self
.config
.get('ovs_controller_keyfile'),
1439 db
=self
.config
["db"], db_lock
=self
.config
["db_lock"], test
=host_test_mode
,
1440 image_path
=self
.config
['host_image_path'], version
=self
.config
['version'],
1441 host_id
='openvim_controller', develop_mode
=host_develop_mode
,
1442 develop_bridge_iface
=bridge_ifaces
,
1443 logger_name
=self
.logger_name
+ ".host.controller",
1444 debug
=self
.config
.get('log_level_host'))
1446 self
.config
['host_threads']['openvim_controller'] = dhcp_host
1448 dhcp_host
.check_connectivity()
1449 except Exception as e
:
1454 def launch_dhcp_server(self
, vlan
, first_ip
, last_ip
, cidr
, gateway
, dns
, routes
):
1456 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1457 :param vlan: vlan identifier
1458 :param first_ip: First dhcp range ip
1459 :param last_ip: Last dhcp range ip
1460 :param cidr: net cidr
1461 :param gateway: net gateway
1464 ip_tools
= IPNetwork(cidr
)
1465 dhcp_netmask
= str(ip_tools
.netmask
)
1466 ip_range
= [first_ip
, last_ip
]
1468 dhcp_path
= self
.config
['ovs_controller_file_path']
1470 controller_host
= self
.get_dhcp_controller()
1472 # controller_host.create_linux_bridge(vlan)
1473 controller_host
.create_dhcp_interfaces(vlan
, first_ip
, dhcp_netmask
)
1474 dhcp_path
= self
.config
['ovs_controller_file_path']
1475 controller_host
.launch_dhcp_server(vlan
, ip_range
, dhcp_netmask
, dhcp_path
, gateway
, dns
, routes
)
1477 def launch_link_bridge_to_ovs(self
, vlan
, gateway
, dhcp_cidr
, links
=None, routes
=None):
1479 Launch creating of connections (veth) between user bridge (link) and OVS
1487 controller_host
= self
.get_dhcp_controller()
1489 if 'iface' in link
and 'nat' not in link
:
1490 controller_host
.create_link_bridge_to_ovs(vlan
, link
['iface'])
1492 controller_host
.create_qrouter_ovs_connection(vlan
, gateway
, dhcp_cidr
)
1493 controller_host
.create_qrouter_br_connection(vlan
, dhcp_cidr
, link
)
1496 controller_host
.add_ns_routes(vlan
, routes
)
1498 def delete_link_bridge_to_ovs(self
, vlan
, links
=None):
1500 Delete connections (veth) between user bridge (link) and OVS
1506 controller_host
= self
.get_dhcp_controller()
1509 if 'iface' in link
and 'nat' not in link
:
1510 controller_host
.remove_link_bridge_to_ovs(vlan
, link
['iface'])
1512 controller_host
.delete_qrouter_connection(vlan
, link
['iface'])
1515 if __name__
== "__main__":
1517 parser
= argparse
.ArgumentParser()
1518 parser
.add_argument("-v","--version", help="show ovim library version", action
="store_true")
1519 parser
.add_argument("--database-version", help="show required database version", action
="store_true")
1520 args
= parser
.parse_args()
1522 print ('openvimd version {} {}'.format(ovim
.get_version(), ovim
.get_version_date()))
1523 print ('(c) Copyright Telefonica')
1524 elif args
.database_version
:
1525 print ('required database version: {}'.format(ovim
.get_database_version()))