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.21-r537"
47 version_date
= "Nov 2017"
48 database_version
= 22 #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', 'password', 'keyfile'),
203 FROM
='hosts', WHERE
={'status': 'ok'})
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 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"], db_lock
=self
.config
["db_lock"],
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
330 ofcs
= self
.get_of_controllers()
333 of_conn
= self
._load
_of
_module
(ofc
)
334 # create ofc thread per of controller
335 self
._create
_ofc
_task
(ofc
['uuid'], ofc
['dpid'], of_conn
)
337 def _create_ofc_task(self
, ofc_uuid
, dpid
, of_conn
):
339 Create an ofc thread for handle each sdn controllers
340 :param ofc_uuid: sdn controller uuid
341 :param dpid: sdn controller dpid
342 :param of_conn: OF_conn module
345 if 'ofcs_thread' not in self
.config
and 'ofcs_thread_dpid' not in self
.config
:
347 ofcs_thread_dpid
= []
349 ofcs_threads
= self
.config
['ofcs_thread']
350 ofcs_thread_dpid
= self
.config
['ofcs_thread_dpid']
352 if ofc_uuid
not in ofcs_threads
:
353 ofc_thread
= self
._create
_ofc
_thread
(of_conn
, ofc_uuid
)
354 if ofc_uuid
== "Default":
355 self
.config
['of_thread'] = ofc_thread
357 ofcs_threads
[ofc_uuid
] = ofc_thread
358 self
.config
['ofcs_thread'] = ofcs_threads
360 ofcs_thread_dpid
.append({dpid
: ofc_thread
})
361 self
.config
['ofcs_thread_dpid'] = ofcs_thread_dpid
363 def _start_ofc_default_task(self
):
365 Create default ofc thread
367 if 'of_controller' not in self
.config \
368 and 'of_controller_ip' not in self
.config \
369 and 'of_controller_port' not in self
.config \
370 and 'of_controller_dpid' not in self
.config
:
375 db_config
['ip'] = self
.config
.get('of_controller_ip')
376 db_config
['port'] = self
.config
.get('of_controller_port')
377 db_config
['dpid'] = self
.config
.get('of_controller_dpid')
378 db_config
['type'] = self
.config
.get('of_controller')
379 db_config
['user'] = self
.config
.get('of_user')
380 db_config
['password'] = self
.config
.get('of_password')
382 # create connector to the openflow controller
383 # load other parameters starting by of_ from config dict in a temporal dict
385 of_conn
= self
._load
_of
_module
(db_config
)
386 # create openflow thread
387 self
._create
_ofc
_task
("Default", db_config
['dpid'], of_conn
)
389 def _load_of_module(self
, db_config
):
391 import python module for each SDN controller supported
392 :param db_config: SDN dn information
396 raise ovimException("No module found it", HTTP_Internal_Server_Error
)
401 if self
.of_test_mode
:
402 return openflow_conn
.OfTestConnector({"name": db_config
['type'],
403 "dpid": db_config
['dpid'],
404 "of_debug": self
.config
['log_level_of']})
408 temp_dict
['of_ip'] = db_config
['ip']
409 temp_dict
['of_port'] = db_config
['port']
410 temp_dict
['of_dpid'] = db_config
['dpid']
411 temp_dict
['of_controller'] = db_config
['type']
412 temp_dict
['of_user'] = db_config
.get('user')
413 temp_dict
['of_password'] = db_config
.get('password')
415 temp_dict
['of_debug'] = self
.config
['log_level_of']
417 if temp_dict
['of_controller'] == 'opendaylight':
420 module
= temp_dict
['of_controller']
422 if module
not in ovim
.of_module
:
424 pkg
= __import__("osm_openvim." + module
)
425 of_conn_module
= getattr(pkg
, module
)
426 ovim
.of_module
[module
] = of_conn_module
427 self
.logger
.debug("Module load from {}".format("osm_openvim." + module
))
428 except Exception as e
:
429 self
.logger
.error("Cannot open openflow controller module of type '%s'", module
)
430 raise ovimException("Cannot open openflow controller of type module '{}'"
431 "Revise it is installed".format(module
),
432 HTTP_Internal_Server_Error
)
434 of_conn_module
= ovim
.of_module
[module
]
435 return of_conn_module
.OF_conn(temp_dict
)
436 except Exception as e
:
437 self
.logger
.error("Cannot open the Openflow controller '%s': %s", type(e
).__name
__, str(e
))
438 raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e
).__name
__, str(e
)),
439 HTTP_Internal_Server_Error
)
441 def _create_ofc_thread(self
, of_conn
, ofc_uuid
="Default"):
443 Create and launch a of thread
446 # create openflow thread
448 #if 'of_controller_nets_with_same_vlan' in self.config:
449 # ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
451 # ofc_net_same_vlan = False
452 ofc_net_same_vlan
= False
454 thread
= oft
.openflow_thread(ofc_uuid
, of_conn
, of_test
=self
.of_test_mode
, db
=self
.config
["db"],
455 db_lock
=self
.config
["db_lock"],
456 pmp_with_same_vlan
=ofc_net_same_vlan
,
457 logger_name
=self
.logger_name
+ ".ofc." + ofc_uuid
,
458 debug
=self
.config
.get('log_level_of'))
459 #r, c = thread.OF_connector.obtain_port_correspondence()
461 # raise ovimException("Cannot get openflow information %s", c)
465 def stop_service(self
):
466 threads
= self
.config
.get('host_threads', {})
467 if 'of_thread' in self
.config
:
468 threads
['of'] = (self
.config
['of_thread'])
469 if 'ofcs_thread' in self
.config
:
470 ofcs_thread
= self
.config
['ofcs_thread']
471 for ofc
in ofcs_thread
:
472 threads
[ofc
] = ofcs_thread
[ofc
]
474 if 'dhcp_thread' in self
.config
:
475 threads
['dhcp'] = (self
.config
['dhcp_thread'])
477 for thread_id
, thread
in threads
.items():
478 if thread_id
== 'openvim_controller':
480 thread
.insert_task("exit")
481 for thread_id
, thread
in threads
.items():
482 if thread_id
== 'openvim_controller':
486 def get_networks(self
, columns
=None, db_filter
={}, limit
=None):
488 Retreive networks available
489 :param columns: List with select query parameters
490 :param db_filter: List with where query parameters
491 :param limit: Query limit result
494 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='nets', WHERE
=db_filter
, LIMIT
=limit
)
497 raise ovimException(str(content
), -result
)
499 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
503 def show_network(self
, network_id
, db_filter
={}):
505 Get network from DB by id
506 :param network_id: net Id
507 :param db_filter: List with where query parameters
512 raise ovimException("Not network id was not found")
513 db_filter
['uuid'] = network_id
515 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
=db_filter
, LIMIT
=100)
518 raise ovimException(str(content
), -result
)
520 raise ovimException("show_network network '%s' not found" % network_id
, -result
)
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
529 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
532 def new_network(self
, network
):
537 tenant_id
= network
.get('tenant_id')
540 result
, _
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
, "enabled": True})
542 raise ovimException("set_network error, no tenant founded", -result
)
546 net_provider
= network
.get('provider')
547 net_type
= network
.get('type')
548 net_vlan
= network
.get("vlan")
549 net_bind_net
= network
.get("bind_net")
550 net_bind_type
= network
.get("bind_type")
551 net_region
= network
.get("region")
552 name
= network
["name"]
554 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
555 vlan_index
= name
.rfind(":")
556 if not net_bind_net
and not net_bind_type
and vlan_index
> 1:
558 vlan_tag
= int(name
[vlan_index
+ 1:])
559 if not vlan_tag
and vlan_tag
< 4096:
560 net_bind_net
= name
[:vlan_index
]
561 net_bind_type
= "vlan:" + name
[vlan_index
+ 1:]
566 # look for a valid net
567 if self
._check
_valid
_uuid
(net_bind_net
):
568 net_bind_key
= "uuid"
570 net_bind_key
= "name"
571 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
573 raise ovimException(' getting nets from db ' + content
, HTTP_Internal_Server_Error
)
575 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
577 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
578 network
["bind_net"] = content
[0]["uuid"]
581 if net_bind_type
[0:5] != "vlan:":
582 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
583 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
584 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
586 network
["bind_type"] = net_bind_type
589 if net_provider
[:9] == "openflow:":
591 if net_type
!= "ptp" and net_type
!= "data":
592 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
598 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
599 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
600 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
602 net_type
= 'bridge_man'
605 net_type
= 'bridge_man'
608 if net_provider
[:7] == 'bridge:':
609 # check it is one of the pre-provisioned bridges
610 bridge_net_name
= net_provider
[7:]
611 for brnet
in self
.config
['bridge_nets']:
612 if brnet
[0] == bridge_net_name
: # free
614 raise ovimException("invalid 'provider:physical', "
615 "bridge '%s' is already used" % bridge_net_name
, HTTP_Conflict
)
619 # if bridge_net==None:
620 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
621 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
624 elif self
.config
['network_type'] == 'bridge' and (net_type
== 'bridge_data' or net_type
== 'bridge_man'):
625 # look for a free precreated nets
626 for brnet
in self
.config
['bridge_nets']:
627 if not brnet
[3]: # free
629 if net_type
== 'bridge_man': # look for the smaller speed
630 if brnet
[2] < bridge_net
[2]:
632 else: # look for the larger speed
633 if brnet
[2] > bridge_net
[2]:
639 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
640 "will overcome this limit", HTTP_Bad_Request
)
642 self
.logger
.debug("using net " + bridge_net
)
643 net_provider
= "bridge:" + bridge_net
[0]
644 net_vlan
= bridge_net
[1]
645 elif net_type
== 'bridge_data' or net_type
== 'bridge_man' and self
.config
['network_type'] == 'ovs':
648 if net_type
== "data" or net_type
== "ptp":
649 net_region
= "__DATA__"
650 elif net_provider
== "OVS":
651 net_region
= "__OVS__"
652 if not net_vlan
and (net_type
== "data" or net_type
== "ptp" or net_provider
== "OVS"):
653 net_vlan
= self
.db
.get_free_net_vlan(net_region
)
655 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error
)
656 if net_provider
== 'OVS':
657 net_provider
= 'OVS' + ":" + str(net_vlan
)
659 network
['provider'] = net_provider
660 network
['type'] = net_type
661 network
['vlan'] = net_vlan
662 network
['region'] = net_region
663 dhcp_integrity
= True
664 if 'enable_dhcp' in network
and network
['enable_dhcp']:
665 dhcp_integrity
= self
._check
_dhcp
_data
_integrity
(network
)
667 if network
.get('links'):
668 network
['links'] = yaml
.safe_dump(network
['links'], default_flow_style
=True, width
=256)
669 if network
.get('dns'):
670 network
['dns'] = yaml
.safe_dump(network
['dns'], default_flow_style
=True, width
=256)
671 if network
.get('routes'):
672 network
['routes'] = yaml
.safe_dump(network
['routes'], default_flow_style
=True, width
=256)
674 result
, content
= self
.db
.new_row('nets', network
, True, True)
675 if result
>= 0 and dhcp_integrity
:
677 bridge_net
[3] = content
678 if self
.config
.get("dhcp_server") and self
.config
['network_type'] == 'bridge': # \
679 if network
["name"] in self
.config
["dhcp_server"].get("nets", ()):
680 self
.config
["dhcp_nets"].append(content
)
681 self
.logger
.debug("dhcp_server: add new net", content
)
682 elif bridge_net
and bridge_net
[0] in self
.config
["dhcp_server"].get("bridge_ifaces", ()):
683 self
.config
["dhcp_nets"].append(content
)
684 self
.logger
.debug("dhcp_server: add new net", content
, content
)
687 raise ovimException("Error posting network", HTTP_Internal_Server_Error
)
688 # TODO kei change update->edit
690 def edit_network(self
, network_id
, network
):
692 Update entwork data byt id
695 # Look for the previous data
696 where_
= {'uuid': network_id
}
697 result
, network_old
= self
.db
.get_table(FROM
='nets', WHERE
=where_
)
699 raise ovimException("Error updating network %s" % network_old
, HTTP_Internal_Server_Error
)
701 raise ovimException('network %s not found' % network_id
, HTTP_Not_Found
)
703 nbports
, content
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
704 WHERE
={'net_id': network_id
}, LIMIT
=100)
706 raise ovimException("http_put_network_id error %d %s" % (result
, network_old
), HTTP_Internal_Server_Error
)
708 if 'type' in network
and network
['type'] != network_old
[0]['type']:
709 raise ovimException("Can not change type of network while having ports attached",
710 HTTP_Method_Not_Allowed
)
711 if 'vlan' in network
and network
['vlan'] != network_old
[0]['vlan']:
712 raise ovimException("Can not change vlan of network while having ports attached",
713 HTTP_Method_Not_Allowed
)
716 net_provider
= network
.get('provider', network_old
[0]['provider'])
717 net_type
= network
.get('type', network_old
[0]['type'])
718 net_bind_net
= network
.get("bind_net")
719 net_bind_type
= network
.get("bind_type")
721 # look for a valid net
722 if self
._check
_valid
_uuid
(net_bind_net
):
723 net_bind_key
= "uuid"
725 net_bind_key
= "name"
726 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
728 raise ovimException('Getting nets from db ' + content
, HTTP_Internal_Server_Error
)
730 raise ovimException("bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
732 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
),
734 network
["bind_net"] = content
[0]["uuid"]
736 if net_bind_type
[0:5] != "vlan:":
737 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
738 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
739 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
742 if net_provider
[:9] == "openflow:":
743 if net_type
!= "ptp" and net_type
!= "data":
744 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request
)
746 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
747 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
748 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
750 # insert in data base
751 result
, content
= self
.db
.update_rows('nets', network
, WHERE
={'uuid': network_id
}, log
=True)
753 # if result > 0 and nbports>0 and 'admin_state_up' in network
754 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
759 self
.net_update_ofc_thread(network_id
)
760 except ovimException
as e
:
761 raise ovimException("Error while launching openflow rules in network '{}' {}"
762 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
763 except Exception as e
:
764 raise ovimException("Error while launching openflow rules in network '{}' {}"
765 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
767 if self
.config
.get("dhcp_server"):
768 if network_id
in self
.config
["dhcp_nets"]:
769 self
.config
["dhcp_nets"].remove(network_id
)
770 if network
.get("name", network_old
[0]["name"]) in self
.config
["dhcp_server"].get("nets", ()):
771 self
.config
["dhcp_nets"].append(network_id
)
773 net_bind
= network
.get("bind_type", network_old
[0]["bind_type"])
774 if net_bind
and net_bind
and net_bind
[:7] == "bridge:" and net_bind
[7:] in self
.config
["dhcp_server"].get(
775 "bridge_ifaces", ()):
776 self
.config
["dhcp_nets"].append(network_id
)
779 raise ovimException(content
, -result
)
781 def delete_network(self
, network_id
):
783 Delete network by network id
784 :param network_id: network id
787 net_data
= self
.show_network(network_id
)
789 # delete from the data base
790 result
, content
= self
.db
.delete_row('nets', network_id
)
793 raise ovimException("Network %s not found " % network_id
, HTTP_Not_Found
)
795 for brnet
in self
.config
['bridge_nets']:
796 if brnet
[3] == network_id
:
799 if self
.config
.get("dhcp_server") and network_id
in self
.config
["dhcp_nets"]:
800 self
.config
["dhcp_nets"].remove(network_id
)
802 if net_data
.get('enable_dhcp'):
803 dhcp_path
= self
.config
['ovs_controller_file_path']
804 dhcp_controller
= self
.get_dhcp_controller()
805 dhcp_controller
.delete_dhcp_server(net_data
['vlan'], network_id
, dhcp_path
)
806 dhcp_controller
.delete_dhcp_port(net_data
['vlan'], network_id
, dhcp_path
)
807 links
= yaml
.load(net_data
.get('links'))
809 links
= yaml
.load(net_data
.get('links'))
810 self
.delete_link_bridge_to_ovs(net_data
['vlan'], links
)
814 raise ovimException("Error deleting network '{}': {}".format(network_id
, content
), -result
)
816 def get_openflow_rules(self
, network_id
=None):
818 Get openflow id from DB
819 :param network_id: Network id, if none all networks will be retrieved
820 :return: Return a list with Openflow rules per net
826 where_
= {"net_id": network_id
}
827 result
, content
= self
.db
.get_table(
828 SELECT
=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
829 WHERE
=where_
, FROM
='of_flows')
832 raise ovimException(str(content
), -result
)
835 def edit_openflow_rules(self
, network_id
=None):
838 To make actions over the net. The action is to reinstall the openflow rules
839 network_id can be 'all'
840 :param network_id: Network id, if none all networks will be retrieved
841 :return : Number of nets updated
848 where_
= {"uuid": network_id
}
849 result
, content
= self
.db
.get_table(SELECT
=("uuid", "type"), WHERE
=where_
, FROM
='nets')
852 raise ovimException(str(content
), -result
)
855 if net
["type"] != "ptp" and net
["type"] != "data":
860 self
.net_update_ofc_thread(net
['uuid'])
861 except ovimException
as e
:
862 raise ovimException("Error updating network'{}' {}".format(net
['uuid'], str(e
)),
863 HTTP_Internal_Server_Error
)
864 except Exception as e
:
865 raise ovimException("Error updating network '{}' {}".format(net
['uuid'], str(e
)),
866 HTTP_Internal_Server_Error
)
870 def delete_openflow_rules(self
, ofc_id
=None):
872 To make actions over the net. The action is to delete ALL openflow rules
873 :return: return operation result
877 if 'Default' in self
.config
['ofcs_thread']:
878 r
, c
= self
.config
['ofcs_thread']['Default'].insert_task("clear-all")
880 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
882 elif ofc_id
in self
.config
['ofcs_thread']:
883 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("clear-all")
887 raise ovimException(str(c
), -r
)
889 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
892 def get_openflow_ports(self
, ofc_id
=None):
894 Obtain switch ports names of openflow controller
895 :return: Return flow ports in DB
898 if 'Default' in self
.config
['ofcs_thread']:
899 conn
= self
.config
['ofcs_thread']['Default'].OF_connector
901 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
903 elif ofc_id
in self
.config
['ofcs_thread']:
904 conn
= self
.config
['ofcs_thread'][ofc_id
].OF_connector
906 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
909 def get_ports(self
, columns
=None, filter={}, limit
=None):
910 # result, content = my.db.get_ports(where_)
911 result
, content
= self
.db
.get_table(SELECT
=columns
, WHERE
=filter, FROM
='ports', LIMIT
=limit
)
913 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
914 raise ovimException(str(content
), -result
)
916 convert_boolean(content
, ('admin_state_up',))
919 def new_port(self
, port_data
):
920 port_data
['type'] = 'external'
921 if port_data
.get('net_id'):
922 # check that new net has the correct type
923 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
925 raise ovimException(str(new_net
), -result
)
926 # insert in data base
927 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
929 if 'net_id' in port_data
:
931 self
.net_update_ofc_thread(port_data
['net_id'])
932 except ovimException
as e
:
933 raise ovimException("Cannot insert a task for updating network '{}' {}"
934 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
935 except Exception as e
:
936 raise ovimException("Cannot insert a task for updating network '{}' {}"
937 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
941 raise ovimException(str(uuid
), -result
)
943 def new_external_port(self
, port_data
):
945 Create new external port and check port mapping correspondence
946 :param port_data: port_data = {
947 'region': 'datacenter region',
948 'compute_node': 'compute node id',
949 'pci': 'pci port address',
952 'tenant_id': 'tenant id',
955 'ip_address': 'ip address - optional'}
959 port_data
['type'] = 'external'
961 if port_data
.get('net_id'):
962 # check that new net has the correct type
963 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
965 raise ovimException(str(new_net
), -result
)
966 # insert in data base
969 if port_data
.get('region'):
970 db_filter
['region'] = port_data
['region']
971 if port_data
.get('pci'):
972 db_filter
['pci'] = port_data
['pci']
973 if port_data
.get('compute_node'):
974 db_filter
['compute_node'] = port_data
['compute_node']
976 columns
= ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
977 port_mapping_data
= self
.get_of_port_mappings(columns
, db_filter
)
979 if not len(port_mapping_data
):
980 raise ovimException("No port mapping founded for '{}'".format(str(db_filter
)),
982 elif len(port_mapping_data
) > 1:
983 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
986 port_data
['ofc_id'] = port_mapping_data
[0]['ofc_id']
987 port_data
['switch_dpid'] = port_mapping_data
[0]['switch_dpid']
988 port_data
['switch_port'] = port_mapping_data
[0]['switch_port']
989 port_data
['switch_mac'] = port_mapping_data
[0]['switch_mac']
991 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
992 if 'region' in port_data
:
993 del port_data
['region']
994 if 'pci' in port_data
:
996 if 'compute_node' in port_data
:
997 del port_data
['compute_node']
999 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
1002 self
.net_update_ofc_thread(port_data
['net_id'], port_data
['ofc_id'])
1003 except ovimException
as e
:
1004 raise ovimException("Cannot insert a task for updating network '{}' {}".
1005 format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
1006 except Exception as e
:
1007 raise ovimException("Cannot insert a task for updating network '{}' {}"
1008 .format(port_data
['net_id'], e
), HTTP_Internal_Server_Error
)
1011 raise ovimException(str(uuid
), -result
)
1013 def net_update_ofc_thread(self
, net_id
, ofc_id
=None, switch_dpid
=None):
1015 Insert a update net task by net id or ofc_id for each ofc thread
1016 :param net_id: network id
1017 :param ofc_id: openflow controller id
1018 :param switch_dpid: switch dpid
1022 raise ovimException("No net_id received", HTTP_Internal_Server_Error
)
1025 c
= 'No valid ofc_id or switch_dpid received'
1028 ports
= self
.get_ports(filter={"net_id": net_id
})
1030 port_ofc_id
= port
.get('ofc_id', None)
1032 ofc_id
= port
['ofc_id']
1033 switch_dpid
= port
['switch_dpid']
1035 #TODO if not ofc_id: look at database table ofcs
1038 # If no ofc_id found it, default ofc_id is used.
1039 if not ofc_id
and not switch_dpid
:
1042 if ofc_id
and ofc_id
in self
.config
['ofcs_thread']:
1043 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("update-net", net_id
)
1046 ofcs_dpid_list
= self
.config
['ofcs_thread_dpid']
1047 for ofc_t
in ofcs_dpid_list
:
1048 if switch_dpid
in ofc_t
:
1049 r
, c
= ofc_t
[switch_dpid
].insert_task("update-net", net_id
)
1052 message
= "Cannot insert a task for updating network '{}', {}".format(net_id
, c
)
1053 self
.logger
.error(message
)
1054 raise ovimException(message
, HTTP_Internal_Server_Error
)
1056 def delete_port(self
, port_id
):
1057 # Look for the previous port data
1058 result
, ports
= self
.db
.get_table(WHERE
={'uuid': port_id
, "type": "external"}, FROM
='ports')
1060 raise ovimException("Cannot get port info from database: {}".format(ports
), http_code
=-result
)
1061 # delete from the data base
1062 result
, content
= self
.db
.delete_row('ports', port_id
)
1064 raise ovimException("External port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1066 raise ovimException("Cannot delete port from database: {}".format(content
), http_code
=-result
)
1068 network
= ports
[0].get('net_id', None)
1073 self
.net_update_ofc_thread(network
, ofc_id
=ports
[0]["ofc_id"], switch_dpid
=ports
[0]["switch_dpid"])
1074 except ovimException
as e
:
1075 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network
, str(e
)),
1076 HTTP_Internal_Server_Error
)
1077 except Exception as e
:
1078 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network
, str(e
)),
1079 HTTP_Internal_Server_Error
)
1083 def edit_port(self
, port_id
, port_data
, admin
=True):
1084 # Look for the previous port data
1085 result
, content
= self
.db
.get_table(FROM
="ports", WHERE
={'uuid': port_id
})
1087 raise ovimException("Cannot get port info from database: {}".format(content
), http_code
=-result
)
1089 raise ovimException("Port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1094 if 'net_id' in port_data
:
1096 old_net
= port
.get('net_id', None)
1097 new_net
= port_data
['net_id']
1098 if old_net
!= new_net
:
1101 nets
.append(new_net
) # put first the new net, so that new openflow rules are created before removing the old ones
1103 nets
.append(old_net
)
1104 if port
['type'] == 'instance:bridge' or port
['type'] == 'instance:ovs':
1105 raise ovimException("bridge interfaces cannot be attached to a different net", http_code
=HTTP_Forbidden
)
1106 elif port
['type'] == 'external' and not admin
:
1107 raise ovimException("Needed admin privileges",http_code
=HTTP_Unauthorized
)
1109 # check that new net has the correct type
1110 result
, new_net_dict
= self
.db
.check_target_net(new_net
, None, port
['type'])
1112 raise ovimException("Error {}".format(new_net_dict
), http_code
=HTTP_Conflict
)
1113 # change VLAN for SR-IOV ports
1114 if result
>= 0 and port
["type"] == "instance:data" and port
["model"] == "VF": # TODO consider also VFnotShared
1116 port_data
["vlan"] = None
1118 port_data
["vlan"] = new_net_dict
["vlan"]
1119 # get host where this VM is allocated
1120 result
, content
= self
.db
.get_table(FROM
="instances", WHERE
={"uuid": port
["instance_id"]})
1122 host_id
= content
[0]["host_id"]
1124 # insert in data base
1126 result
, content
= self
.db
.update_rows('ports', port_data
, WHERE
={'uuid': port_id
}, log
=False)
1127 port
.update(port_data
)
1129 # Insert task to complete actions
1133 self
.net_update_ofc_thread(net_id
, port
["ofc_id"], switch_dpid
=port
["switch_dpid"])
1134 except ovimException
as e
:
1135 raise ovimException("Error updating network'{}' {}".format(net_id
, str(e
)),
1136 HTTP_Internal_Server_Error
)
1137 except Exception as e
:
1138 raise ovimException("Error updating network '{}' {}".format(net_id
, str(e
)),
1139 HTTP_Internal_Server_Error
)
1142 r
, v
= self
.config
['host_threads'][host_id
].insert_task("edit-iface", port_id
, old_net
, new_net
)
1144 self
.logger
.error("Error updating network '{}' {}".format(r
,v
))
1145 # TODO Do something if fails
1149 raise ovimException("Error {}".format(content
), http_code
=-result
)
1151 def new_of_controller(self
, ofc_data
):
1153 Create a new openflow controller into DB
1154 :param ofc_data: Dict openflow controller data
1155 :return: openflow controller dpid
1158 result
, ofc_uuid
= self
.db
.new_row('ofcs', ofc_data
, True, True)
1160 raise ovimException("New ofc Error %s" % ofc_uuid
, HTTP_Internal_Server_Error
)
1162 ofc_data
['uuid'] = ofc_uuid
1163 of_conn
= self
._load
_of
_module
(ofc_data
)
1164 self
._create
_ofc
_task
(ofc_uuid
, ofc_data
['dpid'], of_conn
)
1168 def edit_of_controller(self
, of_id
, ofc_data
):
1170 Edit an openflow controller entry from DB
1174 raise ovimException("No data received during uptade OF contorller", http_code
=HTTP_Internal_Server_Error
)
1176 old_of_controller
= self
.show_of_controller(of_id
)
1178 if old_of_controller
:
1179 result
, content
= self
.db
.update_rows('ofcs', ofc_data
, WHERE
={'uuid': of_id
}, log
=False)
1183 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1186 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1187 http_code
=HTTP_Internal_Server_Error
)
1189 def delete_of_controller(self
, of_id
):
1191 Delete an openflow controller from DB.
1192 :param of_id: openflow controller dpid
1196 ofc
= self
.show_of_controller(of_id
)
1198 result
, content
= self
.db
.delete_row("ofcs", of_id
)
1200 raise ovimException("Cannot delete ofc from database: {}".format(content
), http_code
=-result
)
1202 raise ovimException("ofc {} not found ".format(content
), http_code
=HTTP_Not_Found
)
1204 ofc_thread
= self
.config
['ofcs_thread'][of_id
]
1205 del self
.config
['ofcs_thread'][of_id
]
1206 for ofc_th
in self
.config
['ofcs_thread_dpid']:
1207 if ofc
['dpid'] in ofc_th
:
1208 self
.config
['ofcs_thread_dpid'].remove(ofc_th
)
1210 ofc_thread
.insert_task("exit")
1215 def show_of_controller(self
, uuid
):
1217 Show an openflow controller by dpid from DB.
1218 :param db_filter: List with where query parameters
1222 result
, content
= self
.db
.get_table(FROM
='ofcs', WHERE
={"uuid": uuid
}, LIMIT
=100)
1225 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid
),
1226 http_code
=HTTP_Not_Found
)
1228 raise ovimException("Openflow controller with uuid '{}' error".format(uuid
),
1229 http_code
=HTTP_Internal_Server_Error
)
1232 def get_of_controllers(self
, columns
=None, db_filter
={}, limit
=None):
1234 Show an openflow controllers from DB.
1235 :param columns: List with SELECT query parameters
1236 :param db_filter: List with where query parameters
1237 :param limit: result Limit
1240 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='ofcs', WHERE
=db_filter
, LIMIT
=limit
)
1243 raise ovimException(str(content
), -result
)
1247 def get_tenants(self
, columns
=None, db_filter
={}, limit
=None):
1249 Retrieve tenant list from DB
1250 :param columns: List with SELECT query parameters
1251 :param db_filter: List with where query parameters
1252 :param limit: result limit
1255 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=columns
, WHERE
=db_filter
, LIMIT
=limit
)
1257 raise ovimException('get_tenatns Error {}'.format(str(content
)), -result
)
1259 convert_boolean(content
, ('enabled',))
1262 def show_tenant_id(self
, tenant_id
):
1264 Get tenant from DB by id
1265 :param tenant_id: tenant id
1268 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid', 'name', 'description', 'enabled'),
1269 WHERE
={"uuid": tenant_id
})
1271 raise ovimException(str(content
), -result
)
1273 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1275 convert_boolean(content
, ('enabled',))
1278 def new_tentant(self
, tenant
):
1280 Create a tenant and store in DB
1281 :param tenant: Dictionary with tenant data
1282 :return: the uuid of created tenant. Raise exception upon error
1285 # insert in data base
1286 result
, tenant_uuid
= self
.db
.new_tenant(tenant
)
1291 raise ovimException(str(tenant_uuid
), -result
)
1293 def delete_tentant(self
, tenant_id
):
1295 Delete a tenant from the database.
1296 :param tenant_id: Tenant id
1297 :return: delete tenant id
1301 r
, tenants_flavors
= self
.db
.get_table(FROM
='tenants_flavors', SELECT
=('flavor_id', 'tenant_id'),
1302 WHERE
={'tenant_id': tenant_id
})
1304 tenants_flavors
= ()
1305 r
, tenants_images
= self
.db
.get_table(FROM
='tenants_images', SELECT
=('image_id', 'tenant_id'),
1306 WHERE
={'tenant_id': tenant_id
})
1310 result
, content
= self
.db
.delete_row('tenants', tenant_id
)
1312 raise ovimException("tenant '%s' not found" % tenant_id
, HTTP_Not_Found
)
1314 for flavor
in tenants_flavors
:
1315 self
.db
.delete_row_by_key("flavors", "uuid", flavor
['flavor_id'])
1316 for image
in tenants_images
:
1317 self
.db
.delete_row_by_key("images", "uuid", image
['image_id'])
1320 raise ovimException("Error deleting tenant '%s' " % tenant_id
, HTTP_Internal_Server_Error
)
1322 def edit_tenant(self
, tenant_id
, tenant_data
):
1324 Update a tenant data identified by tenant id
1325 :param tenant_id: tenant id
1326 :param tenant_data: Dictionary with tenant data
1330 # Look for the previous data
1331 result
, tenant_data_old
= self
.db
.get_table(FROM
='tenants', WHERE
={'uuid': tenant_id
})
1333 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id
, tenant_data_old
),
1334 HTTP_Internal_Server_Error
)
1336 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1338 # insert in data base
1339 result
, content
= self
.db
.update_rows('tenants', tenant_data
, WHERE
={'uuid': tenant_id
}, log
=True)
1343 raise ovimException(str(content
), -result
)
1345 def set_of_port_mapping(self
, of_maps
, ofc_id
=None, switch_dpid
=None, region
=None):
1347 Create new port mapping entry
1348 :param of_maps: List with port mapping information
1349 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1350 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1351 :param ofc_id: ofc id
1352 :param switch_dpid: switch dpid
1353 :param region: datacenter region id
1359 map['ofc_id'] = ofc_id
1361 map['switch_dpid'] = switch_dpid
1363 map['region'] = region
1365 map["pci"] = map["pci"].lower()
1367 for of_map
in of_maps
:
1368 result
, uuid
= self
.db
.new_row('of_port_mappings', of_map
, True)
1370 of_map
["uuid"] = uuid
1372 raise ovimException(str(uuid
), -result
)
1375 def clear_of_port_mapping(self
, db_filter
={}):
1377 Clear port mapping filtering using db_filter dict
1378 :param db_filter: Parameter to filter during remove process
1381 result
, content
= self
.db
.delete_row_by_dict(FROM
='of_port_mappings', WHERE
=db_filter
)
1386 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter
)),
1387 HTTP_Internal_Server_Error
)
1389 def get_of_port_mappings(self
, column
=None, db_filter
=None, db_limit
=None):
1391 Retrive port mapping from DB
1396 result
, content
= self
.db
.get_table(SELECT
=column
, WHERE
=db_filter
, FROM
='of_port_mappings', LIMIT
=db_limit
)
1399 self
.logger
.error("get_of_port_mappings Error %d %s", result
, content
)
1400 raise ovimException(str(content
), -result
)
1404 def get_dhcp_controller(self
):
1406 Create an host_thread object for manage openvim controller and not create a thread for itself
1407 :return: dhcp_host openvim controller object
1410 if 'openvim_controller' in self
.config
['host_threads']:
1411 return self
.config
['host_threads']['openvim_controller']
1414 controller_ip
= self
.config
['ovs_controller_ip']
1415 ovs_controller_user
= self
.config
.get('ovs_controller_user')
1417 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
1418 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
1420 dhcp_host
= ht
.host_thread(name
='openvim_controller', user
=ovs_controller_user
, host
=controller_ip
,
1421 password
=self
.config
.get('ovs_controller_password'),
1422 keyfile
=self
.config
.get('ovs_controller_keyfile'),
1423 db
=self
.config
["db"], db_lock
=self
.config
["db_lock"], test
=host_test_mode
,
1424 image_path
=self
.config
['host_image_path'], version
=self
.config
['version'],
1425 host_id
='openvim_controller', develop_mode
=host_develop_mode
,
1426 develop_bridge_iface
=bridge_ifaces
,
1427 logger_name
=self
.logger_name
+ ".host.controller",
1428 debug
=self
.config
.get('log_level_host'))
1430 self
.config
['host_threads']['openvim_controller'] = dhcp_host
1432 dhcp_host
.check_connectivity()
1433 except Exception as e
:
1438 def launch_dhcp_server(self
, vlan
, first_ip
, last_ip
, cidr
, gateway
, dns
, routes
):
1440 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1441 :param vlan: vlan identifier
1442 :param first_ip: First dhcp range ip
1443 :param last_ip: Last dhcp range ip
1444 :param cidr: net cidr
1445 :param gateway: net gateway
1448 ip_tools
= IPNetwork(cidr
)
1449 dhcp_netmask
= str(ip_tools
.netmask
)
1450 ip_range
= [first_ip
, last_ip
]
1452 dhcp_path
= self
.config
['ovs_controller_file_path']
1454 controller_host
= self
.get_dhcp_controller()
1456 # controller_host.create_linux_bridge(vlan)
1457 controller_host
.create_dhcp_interfaces(vlan
, first_ip
, dhcp_netmask
)
1458 dhcp_path
= self
.config
['ovs_controller_file_path']
1459 controller_host
.launch_dhcp_server(vlan
, ip_range
, dhcp_netmask
, dhcp_path
, gateway
, dns
, routes
)
1461 def launch_link_bridge_to_ovs(self
, vlan
, gateway
, dhcp_cidr
, links
=None, routes
=None):
1463 Launch creating of connections (veth) between user bridge (link) and OVS
1471 controller_host
= self
.get_dhcp_controller()
1473 if 'iface' in link
and 'nat' not in link
:
1474 controller_host
.create_link_bridge_to_ovs(vlan
, link
['iface'])
1476 controller_host
.create_qrouter_ovs_connection(vlan
, gateway
, dhcp_cidr
)
1477 controller_host
.create_qrouter_br_connection(vlan
, dhcp_cidr
, link
)
1480 controller_host
.add_ns_routes(vlan
, routes
)
1482 def delete_link_bridge_to_ovs(self
, vlan
, links
=None):
1484 Delete connections (veth) between user bridge (link) and OVS
1490 controller_host
= self
.get_dhcp_controller()
1493 if 'iface' in link
and 'nat' not in link
:
1494 controller_host
.remove_link_bridge_to_ovs(vlan
, link
['iface'])
1496 controller_host
.delete_qrouter_connection(vlan
, link
['iface'])
1499 if __name__
== "__main__":
1501 parser
= argparse
.ArgumentParser()
1502 parser
.add_argument("-v","--version", help="show ovim library version", action
="store_true")
1503 parser
.add_argument("--database-version", help="show required database version", action
="store_true")
1504 args
= parser
.parse_args()
1506 print ('openvimd version {} {}'.format(ovim
.get_version(), ovim
.get_version_date()))
1507 print ('(c) Copyright Telefonica')
1508 elif args
.database_version
:
1509 print ('required database version: {}'.format(ovim
.get_database_version()))