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.24-r540"
47 version_date
= "Mar 2018"
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 network
.get('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 creating network: {}".format(content
), -result
)
689 # TODO kei change update->edit
691 def edit_network(self
, network_id
, network
):
693 Update entwork data byt id
696 # Look for the previous data
697 where_
= {'uuid': network_id
}
698 result
, network_old
= self
.db
.get_table(FROM
='nets', WHERE
=where_
)
700 raise ovimException("Error updating network %s" % network_old
, HTTP_Internal_Server_Error
)
702 raise ovimException('network %s not found' % network_id
, HTTP_Not_Found
)
704 nbports
, content
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
705 WHERE
={'net_id': network_id
}, LIMIT
=100)
707 raise ovimException("http_put_network_id error %d %s" % (result
, network_old
), HTTP_Internal_Server_Error
)
709 if 'type' in network
and network
['type'] != network_old
[0]['type']:
710 raise ovimException("Can not change type of network while having ports attached",
711 HTTP_Method_Not_Allowed
)
712 if 'vlan' in network
and network
['vlan'] != network_old
[0]['vlan']:
713 raise ovimException("Can not change vlan of network while having ports attached",
714 HTTP_Method_Not_Allowed
)
717 net_provider
= network
.get('provider', network_old
[0]['provider'])
718 net_type
= network
.get('type', network_old
[0]['type'])
719 net_bind_net
= network
.get("bind_net")
720 net_bind_type
= network
.get("bind_type")
722 # look for a valid net
723 if self
._check
_valid
_uuid
(net_bind_net
):
724 net_bind_key
= "uuid"
726 net_bind_key
= "name"
727 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
729 raise ovimException('Getting nets from db ' + content
, HTTP_Internal_Server_Error
)
731 raise ovimException("bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
733 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
),
735 network
["bind_net"] = content
[0]["uuid"]
737 if net_bind_type
[0:5] != "vlan:":
738 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
739 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
740 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
743 if net_provider
[:9] == "openflow:":
744 if net_type
!= "ptp" and net_type
!= "data":
745 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request
)
747 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
748 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
749 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
751 # insert in data base
752 result
, content
= self
.db
.update_rows('nets', network
, WHERE
={'uuid': network_id
}, log
=True)
754 # if result > 0 and nbports>0 and 'admin_state_up' in network
755 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
760 self
.net_update_ofc_thread(network_id
)
761 except ovimException
as e
:
762 raise ovimException("Error while launching openflow rules in network '{}' {}"
763 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
764 except Exception as e
:
765 raise ovimException("Error while launching openflow rules in network '{}' {}"
766 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
768 if self
.config
.get("dhcp_server"):
769 if network_id
in self
.config
["dhcp_nets"]:
770 self
.config
["dhcp_nets"].remove(network_id
)
771 if network
.get("name", network_old
[0]["name"]) in self
.config
["dhcp_server"].get("nets", ()):
772 self
.config
["dhcp_nets"].append(network_id
)
774 net_bind
= network
.get("bind_type", network_old
[0]["bind_type"])
775 if net_bind
and net_bind
and net_bind
[:7] == "bridge:" and net_bind
[7:] in self
.config
["dhcp_server"].get(
776 "bridge_ifaces", ()):
777 self
.config
["dhcp_nets"].append(network_id
)
780 raise ovimException(content
, -result
)
782 def delete_network(self
, network_id
):
784 Delete network by network id
785 :param network_id: network id
788 net_data
= self
.show_network(network_id
)
790 # delete from the data base
791 result
, content
= self
.db
.delete_row('nets', network_id
)
794 raise ovimException("Network %s not found " % network_id
, HTTP_Not_Found
)
796 for brnet
in self
.config
['bridge_nets']:
797 if brnet
[3] == network_id
:
800 if self
.config
.get("dhcp_server") and network_id
in self
.config
["dhcp_nets"]:
801 self
.config
["dhcp_nets"].remove(network_id
)
803 if net_data
.get('enable_dhcp'):
804 dhcp_path
= self
.config
['ovs_controller_file_path']
805 dhcp_controller
= self
.get_dhcp_controller()
806 dhcp_controller
.delete_dhcp_server(net_data
['vlan'], network_id
, dhcp_path
)
807 dhcp_controller
.delete_dhcp_port(net_data
['vlan'], network_id
, dhcp_path
)
808 links
= yaml
.load(net_data
.get('links'))
810 links
= yaml
.load(net_data
.get('links'))
811 self
.delete_link_bridge_to_ovs(net_data
['vlan'], links
)
815 raise ovimException("Error deleting network '{}': {}".format(network_id
, content
), -result
)
817 def get_openflow_rules(self
, network_id
=None):
819 Get openflow id from DB
820 :param network_id: Network id, if none all networks will be retrieved
821 :return: Return a list with Openflow rules per net
827 where_
= {"net_id": network_id
}
828 result
, content
= self
.db
.get_table(
829 SELECT
=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
830 WHERE
=where_
, FROM
='of_flows')
833 raise ovimException(str(content
), -result
)
836 def edit_openflow_rules(self
, network_id
=None):
839 To make actions over the net. The action is to reinstall the openflow rules
840 network_id can be 'all'
841 :param network_id: Network id, if none all networks will be retrieved
842 :return : Number of nets updated
849 where_
= {"uuid": network_id
}
850 result
, content
= self
.db
.get_table(SELECT
=("uuid", "type"), WHERE
=where_
, FROM
='nets')
853 raise ovimException(str(content
), -result
)
856 if net
["type"] != "ptp" and net
["type"] != "data":
861 self
.net_update_ofc_thread(net
['uuid'])
862 except ovimException
as e
:
863 raise ovimException("Error updating network'{}' {}".format(net
['uuid'], str(e
)),
864 HTTP_Internal_Server_Error
)
865 except Exception as e
:
866 raise ovimException("Error updating network '{}' {}".format(net
['uuid'], str(e
)),
867 HTTP_Internal_Server_Error
)
871 def delete_openflow_rules(self
, ofc_id
=None):
873 To make actions over the net. The action is to delete ALL openflow rules
874 :return: return operation result
878 if 'Default' in self
.config
['ofcs_thread']:
879 r
, c
= self
.config
['ofcs_thread']['Default'].insert_task("clear-all")
881 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
883 elif ofc_id
in self
.config
['ofcs_thread']:
884 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("clear-all")
888 raise ovimException(str(c
), -r
)
890 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
893 def get_openflow_ports(self
, ofc_id
=None):
895 Obtain switch ports names of openflow controller
896 :return: Return flow ports in DB
899 if 'Default' in self
.config
['ofcs_thread']:
900 conn
= self
.config
['ofcs_thread']['Default'].OF_connector
902 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
904 elif ofc_id
in self
.config
['ofcs_thread']:
905 conn
= self
.config
['ofcs_thread'][ofc_id
].OF_connector
907 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
910 def get_ports(self
, columns
=None, filter={}, limit
=None):
911 # result, content = my.db.get_ports(where_)
912 result
, content
= self
.db
.get_table(SELECT
=columns
, WHERE
=filter, FROM
='ports', LIMIT
=limit
)
914 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
915 raise ovimException(str(content
), -result
)
917 convert_boolean(content
, ('admin_state_up',))
920 def new_port(self
, port_data
):
921 port_data
['type'] = 'external'
922 if port_data
.get('net_id'):
923 # check that new net has the correct type
924 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
926 raise ovimException(str(new_net
), -result
)
927 # insert in data base
928 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
930 if 'net_id' in port_data
:
932 self
.net_update_ofc_thread(port_data
['net_id'])
933 except ovimException
as e
:
934 raise ovimException("Cannot insert a task for updating network '{}' {}"
935 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
936 except Exception as e
:
937 raise ovimException("Cannot insert a task for updating network '{}' {}"
938 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
942 raise ovimException(str(uuid
), -result
)
944 def new_external_port(self
, port_data
):
946 Create new external port and check port mapping correspondence
947 :param port_data: port_data = {
948 'region': 'datacenter region',
949 'compute_node': 'compute node id',
950 'pci': 'pci port address',
953 'tenant_id': 'tenant id',
956 'ip_address': 'ip address - optional'}
960 port_data
['type'] = 'external'
962 if port_data
.get('net_id'):
963 # check that new net has the correct type
964 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
966 raise ovimException(str(new_net
), -result
)
967 # insert in data base
970 if port_data
.get('region'):
971 db_filter
['region'] = port_data
['region']
972 if port_data
.get('pci'):
973 db_filter
['pci'] = port_data
['pci']
974 if port_data
.get('compute_node'):
975 db_filter
['compute_node'] = port_data
['compute_node']
977 columns
= ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
978 port_mapping_data
= self
.get_of_port_mappings(columns
, db_filter
)
980 if not len(port_mapping_data
):
981 raise ovimException("No port mapping founded for '{}'".format(str(db_filter
)),
983 elif len(port_mapping_data
) > 1:
984 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
987 port_data
['ofc_id'] = port_mapping_data
[0]['ofc_id']
988 port_data
['switch_dpid'] = port_mapping_data
[0]['switch_dpid']
989 port_data
['switch_port'] = port_mapping_data
[0]['switch_port']
990 port_data
['switch_mac'] = port_mapping_data
[0]['switch_mac']
992 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
993 if 'region' in port_data
:
994 del port_data
['region']
995 if 'pci' in port_data
:
997 if 'compute_node' in port_data
:
998 del port_data
['compute_node']
1000 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
1003 self
.net_update_ofc_thread(port_data
['net_id'], port_data
['ofc_id'])
1004 except ovimException
as e
:
1005 raise ovimException("Cannot insert a task for updating network '{}' {}".
1006 format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
1007 except Exception as e
:
1008 raise ovimException("Cannot insert a task for updating network '{}' {}"
1009 .format(port_data
['net_id'], e
), HTTP_Internal_Server_Error
)
1012 raise ovimException(str(uuid
), -result
)
1014 def net_update_ofc_thread(self
, net_id
, ofc_id
=None, switch_dpid
=None):
1016 Insert a update net task by net id or ofc_id for each ofc thread
1017 :param net_id: network id
1018 :param ofc_id: openflow controller id
1019 :param switch_dpid: switch dpid
1023 raise ovimException("No net_id received", HTTP_Internal_Server_Error
)
1026 c
= 'No valid ofc_id or switch_dpid received'
1029 ports
= self
.get_ports(filter={"net_id": net_id
})
1031 port_ofc_id
= port
.get('ofc_id', None)
1033 ofc_id
= port
['ofc_id']
1034 switch_dpid
= port
['switch_dpid']
1036 #TODO if not ofc_id: look at database table ofcs
1039 # If no ofc_id found it, default ofc_id is used.
1040 if not ofc_id
and not switch_dpid
:
1043 if ofc_id
and ofc_id
in self
.config
['ofcs_thread']:
1044 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("update-net", net_id
)
1047 ofcs_dpid_list
= self
.config
['ofcs_thread_dpid']
1048 for ofc_t
in ofcs_dpid_list
:
1049 if switch_dpid
in ofc_t
:
1050 r
, c
= ofc_t
[switch_dpid
].insert_task("update-net", net_id
)
1053 message
= "Cannot insert a task for updating network '{}', {}".format(net_id
, c
)
1054 self
.logger
.error(message
)
1055 raise ovimException(message
, HTTP_Internal_Server_Error
)
1057 def delete_port(self
, port_id
):
1058 # Look for the previous port data
1059 result
, ports
= self
.db
.get_table(WHERE
={'uuid': port_id
, "type": "external"}, FROM
='ports')
1061 raise ovimException("Cannot get port info from database: {}".format(ports
), http_code
=-result
)
1062 # delete from the data base
1063 result
, content
= self
.db
.delete_row('ports', port_id
)
1065 raise ovimException("External port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1067 raise ovimException("Cannot delete port from database: {}".format(content
), http_code
=-result
)
1069 network
= ports
[0].get('net_id', None)
1074 self
.net_update_ofc_thread(network
, ofc_id
=ports
[0]["ofc_id"], switch_dpid
=ports
[0]["switch_dpid"])
1075 except ovimException
as e
:
1076 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network
, str(e
)),
1077 HTTP_Internal_Server_Error
)
1078 except Exception as e
:
1079 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network
, str(e
)),
1080 HTTP_Internal_Server_Error
)
1084 def edit_port(self
, port_id
, port_data
, admin
=True):
1085 # Look for the previous port data
1086 result
, content
= self
.db
.get_table(FROM
="ports", WHERE
={'uuid': port_id
})
1088 raise ovimException("Cannot get port info from database: {}".format(content
), http_code
=-result
)
1090 raise ovimException("Port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1095 if 'net_id' in port_data
:
1097 old_net
= port
.get('net_id', None)
1098 new_net
= port_data
['net_id']
1099 if old_net
!= new_net
:
1102 nets
.append(new_net
) # put first the new net, so that new openflow rules are created before removing the old ones
1104 nets
.append(old_net
)
1105 if port
['type'] == 'instance:bridge' or port
['type'] == 'instance:ovs':
1106 raise ovimException("bridge interfaces cannot be attached to a different net", http_code
=HTTP_Forbidden
)
1107 elif port
['type'] == 'external' and not admin
:
1108 raise ovimException("Needed admin privileges",http_code
=HTTP_Unauthorized
)
1110 # check that new net has the correct type
1111 result
, new_net_dict
= self
.db
.check_target_net(new_net
, None, port
['type'])
1113 raise ovimException("Error {}".format(new_net_dict
), http_code
=HTTP_Conflict
)
1114 # change VLAN for SR-IOV ports
1115 if result
>= 0 and port
["type"] == "instance:data" and port
["model"] == "VF": # TODO consider also VFnotShared
1117 port_data
["vlan"] = None
1119 port_data
["vlan"] = new_net_dict
["vlan"]
1120 # get host where this VM is allocated
1121 result
, content
= self
.db
.get_table(FROM
="instances", WHERE
={"uuid": port
["instance_id"]})
1123 host_id
= content
[0]["host_id"]
1125 # insert in data base
1127 result
, content
= self
.db
.update_rows('ports', port_data
, WHERE
={'uuid': port_id
}, log
=False)
1128 port
.update(port_data
)
1130 # Insert task to complete actions
1134 self
.net_update_ofc_thread(net_id
, port
["ofc_id"], switch_dpid
=port
["switch_dpid"])
1135 except ovimException
as e
:
1136 raise ovimException("Error updating network'{}' {}".format(net_id
, str(e
)),
1137 HTTP_Internal_Server_Error
)
1138 except Exception as e
:
1139 raise ovimException("Error updating network '{}' {}".format(net_id
, str(e
)),
1140 HTTP_Internal_Server_Error
)
1143 r
, v
= self
.config
['host_threads'][host_id
].insert_task("edit-iface", port_id
, old_net
, new_net
)
1145 self
.logger
.error("Error updating network '{}' {}".format(r
,v
))
1146 # TODO Do something if fails
1150 raise ovimException("Error {}".format(content
), http_code
=-result
)
1152 def new_of_controller(self
, ofc_data
):
1154 Create a new openflow controller into DB
1155 :param ofc_data: Dict openflow controller data
1156 :return: openflow controller dpid
1159 result
, ofc_uuid
= self
.db
.new_row('ofcs', ofc_data
, True, True)
1161 raise ovimException("New ofc Error %s" % ofc_uuid
, HTTP_Internal_Server_Error
)
1163 ofc_data
['uuid'] = ofc_uuid
1164 of_conn
= self
._load
_of
_module
(ofc_data
)
1165 self
._create
_ofc
_task
(ofc_uuid
, ofc_data
['dpid'], of_conn
)
1169 def edit_of_controller(self
, of_id
, ofc_data
):
1171 Edit an openflow controller entry from DB
1175 raise ovimException("No data received during uptade OF contorller", http_code
=HTTP_Internal_Server_Error
)
1177 old_of_controller
= self
.show_of_controller(of_id
)
1179 if old_of_controller
:
1180 result
, content
= self
.db
.update_rows('ofcs', ofc_data
, WHERE
={'uuid': of_id
}, log
=False)
1184 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1187 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1188 http_code
=HTTP_Internal_Server_Error
)
1190 def delete_of_controller(self
, of_id
):
1192 Delete an openflow controller from DB.
1193 :param of_id: openflow controller dpid
1197 ofc
= self
.show_of_controller(of_id
)
1199 result
, content
= self
.db
.delete_row("ofcs", of_id
)
1201 raise ovimException("Cannot delete ofc from database: {}".format(content
), http_code
=-result
)
1203 raise ovimException("ofc {} not found ".format(content
), http_code
=HTTP_Not_Found
)
1205 ofc_thread
= self
.config
['ofcs_thread'][of_id
]
1206 del self
.config
['ofcs_thread'][of_id
]
1207 for ofc_th
in self
.config
['ofcs_thread_dpid']:
1208 if ofc
['dpid'] in ofc_th
:
1209 self
.config
['ofcs_thread_dpid'].remove(ofc_th
)
1211 ofc_thread
.insert_task("exit")
1216 def show_of_controller(self
, uuid
):
1218 Show an openflow controller by dpid from DB.
1219 :param db_filter: List with where query parameters
1223 result
, content
= self
.db
.get_table(FROM
='ofcs', WHERE
={"uuid": uuid
}, LIMIT
=100)
1226 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid
),
1227 http_code
=HTTP_Not_Found
)
1229 raise ovimException("Openflow controller with uuid '{}' error".format(uuid
),
1230 http_code
=HTTP_Internal_Server_Error
)
1233 def get_of_controllers(self
, columns
=None, db_filter
={}, limit
=None):
1235 Show an openflow controllers from DB.
1236 :param columns: List with SELECT query parameters
1237 :param db_filter: List with where query parameters
1238 :param limit: result Limit
1241 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='ofcs', WHERE
=db_filter
, LIMIT
=limit
)
1244 raise ovimException(str(content
), -result
)
1248 def get_tenants(self
, columns
=None, db_filter
={}, limit
=None):
1250 Retrieve tenant list 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(FROM
='tenants', SELECT
=columns
, WHERE
=db_filter
, LIMIT
=limit
)
1258 raise ovimException('get_tenatns Error {}'.format(str(content
)), -result
)
1260 convert_boolean(content
, ('enabled',))
1263 def show_tenant_id(self
, tenant_id
):
1265 Get tenant from DB by id
1266 :param tenant_id: tenant id
1269 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid', 'name', 'description', 'enabled'),
1270 WHERE
={"uuid": tenant_id
})
1272 raise ovimException(str(content
), -result
)
1274 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1276 convert_boolean(content
, ('enabled',))
1279 def new_tentant(self
, tenant
):
1281 Create a tenant and store in DB
1282 :param tenant: Dictionary with tenant data
1283 :return: the uuid of created tenant. Raise exception upon error
1286 # insert in data base
1287 result
, tenant_uuid
= self
.db
.new_tenant(tenant
)
1292 raise ovimException(str(tenant_uuid
), -result
)
1294 def delete_tentant(self
, tenant_id
):
1296 Delete a tenant from the database.
1297 :param tenant_id: Tenant id
1298 :return: delete tenant id
1302 r
, tenants_flavors
= self
.db
.get_table(FROM
='tenants_flavors', SELECT
=('flavor_id', 'tenant_id'),
1303 WHERE
={'tenant_id': tenant_id
})
1305 tenants_flavors
= ()
1306 r
, tenants_images
= self
.db
.get_table(FROM
='tenants_images', SELECT
=('image_id', 'tenant_id'),
1307 WHERE
={'tenant_id': tenant_id
})
1311 result
, content
= self
.db
.delete_row('tenants', tenant_id
)
1313 raise ovimException("tenant '%s' not found" % tenant_id
, HTTP_Not_Found
)
1315 for flavor
in tenants_flavors
:
1316 self
.db
.delete_row_by_key("flavors", "uuid", flavor
['flavor_id'])
1317 for image
in tenants_images
:
1318 self
.db
.delete_row_by_key("images", "uuid", image
['image_id'])
1321 raise ovimException("Error deleting tenant '%s' " % tenant_id
, HTTP_Internal_Server_Error
)
1323 def edit_tenant(self
, tenant_id
, tenant_data
):
1325 Update a tenant data identified by tenant id
1326 :param tenant_id: tenant id
1327 :param tenant_data: Dictionary with tenant data
1331 # Look for the previous data
1332 result
, tenant_data_old
= self
.db
.get_table(FROM
='tenants', WHERE
={'uuid': tenant_id
})
1334 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id
, tenant_data_old
),
1335 HTTP_Internal_Server_Error
)
1337 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1339 # insert in data base
1340 result
, content
= self
.db
.update_rows('tenants', tenant_data
, WHERE
={'uuid': tenant_id
}, log
=True)
1344 raise ovimException(str(content
), -result
)
1346 def set_of_port_mapping(self
, of_maps
, ofc_id
=None, switch_dpid
=None, region
=None):
1348 Create new port mapping entry
1349 :param of_maps: List with port mapping information
1350 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1351 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1352 :param ofc_id: ofc id
1353 :param switch_dpid: switch dpid
1354 :param region: datacenter region id
1360 map['ofc_id'] = ofc_id
1362 map['switch_dpid'] = switch_dpid
1364 map['region'] = region
1366 map["pci"] = map["pci"].lower()
1368 for of_map
in of_maps
:
1369 result
, uuid
= self
.db
.new_row('of_port_mappings', of_map
, True)
1371 of_map
["uuid"] = uuid
1373 raise ovimException(str(uuid
), -result
)
1376 def clear_of_port_mapping(self
, db_filter
={}):
1378 Clear port mapping filtering using db_filter dict
1379 :param db_filter: Parameter to filter during remove process
1382 result
, content
= self
.db
.delete_row_by_dict(FROM
='of_port_mappings', WHERE
=db_filter
)
1387 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter
)),
1388 HTTP_Internal_Server_Error
)
1390 def get_of_port_mappings(self
, column
=None, db_filter
=None, db_limit
=None):
1392 Retrive port mapping from DB
1397 result
, content
= self
.db
.get_table(SELECT
=column
, WHERE
=db_filter
, FROM
='of_port_mappings', LIMIT
=db_limit
)
1400 self
.logger
.error("get_of_port_mappings Error %d %s", result
, content
)
1401 raise ovimException(str(content
), -result
)
1405 def get_dhcp_controller(self
):
1407 Create an host_thread object for manage openvim controller and not create a thread for itself
1408 :return: dhcp_host openvim controller object
1411 if 'openvim_controller' in self
.config
['host_threads']:
1412 return self
.config
['host_threads']['openvim_controller']
1415 controller_ip
= self
.config
['ovs_controller_ip']
1416 ovs_controller_user
= self
.config
.get('ovs_controller_user')
1418 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
1419 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
1421 dhcp_host
= ht
.host_thread(name
='openvim_controller', user
=ovs_controller_user
, host
=controller_ip
,
1422 password
=self
.config
.get('ovs_controller_password'),
1423 keyfile
=self
.config
.get('ovs_controller_keyfile'),
1424 db
=self
.config
["db"], db_lock
=self
.config
["db_lock"], test
=host_test_mode
,
1425 image_path
=self
.config
['host_image_path'], version
=self
.config
['version'],
1426 host_id
='openvim_controller', develop_mode
=host_develop_mode
,
1427 develop_bridge_iface
=bridge_ifaces
,
1428 logger_name
=self
.logger_name
+ ".host.controller",
1429 debug
=self
.config
.get('log_level_host'))
1431 self
.config
['host_threads']['openvim_controller'] = dhcp_host
1433 dhcp_host
.check_connectivity()
1434 except Exception as e
:
1439 def launch_dhcp_server(self
, vlan
, first_ip
, last_ip
, cidr
, gateway
, dns
, routes
):
1441 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1442 :param vlan: vlan identifier
1443 :param first_ip: First dhcp range ip
1444 :param last_ip: Last dhcp range ip
1445 :param cidr: net cidr
1446 :param gateway: net gateway
1449 ip_tools
= IPNetwork(cidr
)
1450 dhcp_netmask
= str(ip_tools
.netmask
)
1451 ip_range
= [first_ip
, last_ip
]
1453 dhcp_path
= self
.config
['ovs_controller_file_path']
1455 controller_host
= self
.get_dhcp_controller()
1457 # controller_host.create_linux_bridge(vlan)
1458 controller_host
.create_dhcp_interfaces(vlan
, first_ip
, dhcp_netmask
)
1459 dhcp_path
= self
.config
['ovs_controller_file_path']
1460 controller_host
.launch_dhcp_server(vlan
, ip_range
, dhcp_netmask
, dhcp_path
, gateway
, dns
, routes
)
1462 def launch_link_bridge_to_ovs(self
, vlan
, gateway
, dhcp_cidr
, links
=None, routes
=None):
1464 Launch creating of connections (veth) between user bridge (link) and OVS
1472 controller_host
= self
.get_dhcp_controller()
1474 if 'iface' in link
and 'nat' not in link
:
1475 controller_host
.create_link_bridge_to_ovs(vlan
, link
['iface'])
1477 controller_host
.create_qrouter_ovs_connection(vlan
, gateway
, dhcp_cidr
)
1478 controller_host
.create_qrouter_br_connection(vlan
, dhcp_cidr
, link
)
1481 controller_host
.add_ns_routes(vlan
, routes
)
1483 def delete_link_bridge_to_ovs(self
, vlan
, links
=None):
1485 Delete connections (veth) between user bridge (link) and OVS
1491 controller_host
= self
.get_dhcp_controller()
1494 if 'iface' in link
and 'nat' not in link
:
1495 controller_host
.remove_link_bridge_to_ovs(vlan
, link
['iface'])
1497 controller_host
.delete_qrouter_connection(vlan
, link
['iface'])
1500 if __name__
== "__main__":
1502 parser
= argparse
.ArgumentParser()
1503 parser
.add_argument("-v","--version", help="show ovim library version", action
="store_true")
1504 parser
.add_argument("--database-version", help="show required database version", action
="store_true")
1505 args
= parser
.parse_args()
1507 print ('openvimd version {} {}'.format(ovim
.get_version(), ovim
.get_version_date()))
1508 print ('(c) Copyright Telefonica')
1509 elif args
.database_version
:
1510 print ('required database version: {}'.format(ovim
.get_database_version()))