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.
30 __author__
= "Alfonso Tierno, Leonardo Mirabal"
31 __date__
= "$06-Feb-2017 12:07:15$"
32 __version__
= "0.5.10-r526"
33 version_date
= "Apr 2017"
34 database_version
= "0.17" #expected database schema version
40 import host_thread
as ht
41 import dhcp_thread
as dt
42 import openflow_thread
as oft
43 from netaddr
import IPNetwork
44 from jsonschema
import validate
as js_v
, exceptions
as js_e
48 HTTP_Bad_Request
= 400
49 HTTP_Unauthorized
= 401
52 HTTP_Method_Not_Allowed
= 405
53 HTTP_Not_Acceptable
= 406
54 HTTP_Request_Timeout
= 408
56 HTTP_Service_Unavailable
= 503
57 HTTP_Internal_Server_Error
= 500
60 def convert_boolean(data
, items
):
61 '''Check recursively the content of data, and if there is an key contained in items, convert value from string to boolean
62 It assumes that bandwidth is well formed
64 'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
65 'items': tuple of keys to convert
69 if type(data
) is dict:
71 if type(data
[k
]) is dict or type(data
[k
]) is tuple or type(data
[k
]) is list:
72 convert_boolean(data
[k
], items
)
74 if type(data
[k
]) is str:
75 if data
[k
] == "false":
77 elif data
[k
] == "true":
79 if type(data
) is tuple or type(data
) is list:
81 if type(k
) is dict or type(k
) is tuple or type(k
) is list:
82 convert_boolean(k
, items
)
86 class ovimException(Exception):
87 def __init__(self
, message
, http_code
=HTTP_Bad_Request
):
88 self
.http_code
= http_code
89 Exception.__init
__(self
, message
)
93 running_info
= {} #TODO OVIM move the info of running threads from config_dic to this static variable
96 def __init__(self
, configuration
):
97 self
.config
= configuration
98 self
.logger_name
= configuration
.get("logger_name", "openvim")
99 self
.logger
= logging
.getLogger(self
.logger_name
)
101 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
[2])
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 raise ovimException("DATABASE is not a VIM one or it is a '0.0' version. Try to upgrade to version '{}' with "\
176 "'./database_utils/migrate_vim_db.sh'".format(database_version
) )
177 elif r
[1] != database_version
:
178 raise ovimException("DATABASE wrong version '{}'. Try to upgrade/downgrade to version '{}' with "\
179 "'./database_utils/migrate_vim_db.sh'".format(r
[1], database_version
) )
180 self
.logger
.critical("Starting ovim server version: '{} {}' database version '{}'".format(
181 self
.get_version(), self
.get_version_date(), self
.get_database_version()))
182 # create database connection for openflow threads
183 self
.db_of
= self
._create
_database
_connection
()
184 self
.config
["db"] = self
.db_of
185 self
.db_lock
= threading
.Lock()
186 self
.config
["db_lock"] = self
.db_lock
188 self
.of_test_mode
= False if self
.config
['mode'] == 'normal' or self
.config
['mode'] == "OF only" else True
189 # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge,
192 self
.config
['dhcp_nets'] = []
193 self
.config
['bridge_nets'] = []
194 for bridge
, vlan_speed
in self
.config
["bridge_ifaces"].items():
195 # skip 'development_bridge'
196 if self
.config
['mode'] == 'development' and self
.config
['development_bridge'] == bridge
:
198 self
.config
['bridge_nets'].append([bridge
, vlan_speed
[0], vlan_speed
[1], None])
200 # check if this bridge is already used (present at database) for a network)
201 used_bridge_nets
= []
202 for brnet
in self
.config
['bridge_nets']:
203 r
, nets
= self
.db
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'provider': "bridge:" + brnet
[0]})
205 brnet
[3] = nets
[0]['uuid']
206 used_bridge_nets
.append(brnet
[0])
207 if self
.config
.get("dhcp_server"):
208 if brnet
[0] in self
.config
["dhcp_server"]["bridge_ifaces"]:
209 self
.config
['dhcp_nets'].append(nets
[0]['uuid'])
210 if len(used_bridge_nets
) > 0:
211 self
.logger
.info("found used bridge nets: " + ",".join(used_bridge_nets
))
212 # get nets used by dhcp
213 if self
.config
.get("dhcp_server"):
214 for net
in self
.config
["dhcp_server"].get("nets", ()):
215 r
, nets
= self
.db
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'name': net
})
217 self
.config
['dhcp_nets'].append(nets
[0]['uuid'])
220 self
._start
_ofc
_default
_task
()
222 # OFC per tenant in DB
223 self
._start
_of
_db
_tasks
()
225 # create dhcp_server thread
226 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
227 dhcp_params
= self
.config
.get("dhcp_server")
229 thread
= dt
.dhcp_thread(dhcp_params
=dhcp_params
, test
=host_test_mode
, dhcp_nets
=self
.config
["dhcp_nets"],
230 db
=self
.db_of
, db_lock
=self
.db_lock
, debug
=self
.config
['log_level_of'])
232 self
.config
['dhcp_thread'] = thread
234 # Create one thread for each host
235 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
236 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
237 host_develop_bridge_iface
= self
.config
.get('development_bridge', None)
239 # get host list from data base before starting threads
240 r
, hosts
= self
.db
.get_table(SELECT
=('name', 'ip_name', 'user', 'uuid'), FROM
='hosts', WHERE
={'status': 'ok'})
242 raise ovimException("Cannot get hosts from database {}".format(hosts
))
244 self
.config
['host_threads'] = {}
246 host
['image_path'] = '/opt/VNF/images/openvim'
247 thread
= ht
.host_thread(name
=host
['name'], user
=host
['user'], host
=host
['ip_name'], db
=self
.db_of
,
248 db_lock
=self
.db_lock
, test
=host_test_mode
, image_path
=self
.config
['image_path'],
249 version
=self
.config
['version'], host_id
=host
['uuid'], develop_mode
=host_develop_mode
,
250 develop_bridge_iface
=host_develop_bridge_iface
)
252 self
.config
['host_threads'][host
['uuid']] = thread
254 # create ovs dhcp thread
255 result
, content
= self
.db
.get_table(FROM
='nets')
257 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
258 raise ovimException(str(content
), -result
)
261 net_type
= net
['type']
262 if (net_type
== 'bridge_data' or net_type
== 'bridge_man') \
263 and net
["provider"][:4] == 'OVS:' and net
["enable_dhcp"] == "true":
264 self
.launch_dhcp_server(net
['vlan'],
265 net
['dhcp_first_ip'],
270 def _start_of_db_tasks(self
):
272 Start ofc task for existing ofcs in database
277 ofcs
= self
.get_of_controllers()
280 of_conn
= self
._load
_of
_module
(ofc
)
281 # create ofc thread per of controller
282 self
._create
_ofc
_task
(ofc
['uuid'], ofc
['dpid'], of_conn
)
284 def _create_ofc_task(self
, ofc_uuid
, dpid
, of_conn
):
286 Create an ofc thread for handle each sdn controllers
287 :param ofc_uuid: sdn controller uuid
288 :param dpid: sdn controller dpid
289 :param of_conn: OF_conn module
292 if 'ofcs_thread' not in self
.config
and 'ofcs_thread_dpid' not in self
.config
:
294 ofcs_thread_dpid
= []
296 ofcs_threads
= self
.config
['ofcs_thread']
297 ofcs_thread_dpid
= self
.config
['ofcs_thread_dpid']
299 if ofc_uuid
not in ofcs_threads
:
300 ofc_thread
= self
._create
_ofc
_thread
(of_conn
, ofc_uuid
)
301 if ofc_uuid
== "Default":
302 self
.config
['of_thread'] = ofc_thread
304 ofcs_threads
[ofc_uuid
] = ofc_thread
305 self
.config
['ofcs_thread'] = ofcs_threads
307 ofcs_thread_dpid
.append({dpid
: ofc_thread
})
308 self
.config
['ofcs_thread_dpid'] = ofcs_thread_dpid
310 def _start_ofc_default_task(self
):
312 Create default ofc thread
314 if 'of_controller' not in self
.config \
315 and 'of_controller_ip' not in self
.config \
316 and 'of_controller_port' not in self
.config \
317 and 'of_controller_dpid' not in self
.config
:
322 db_config
['ip'] = self
.config
.get('of_controller_ip')
323 db_config
['port'] = self
.config
.get('of_controller_port')
324 db_config
['dpid'] = self
.config
.get('of_controller_dpid')
325 db_config
['type'] = self
.config
.get('of_controller')
326 db_config
['user'] = self
.config
.get('of_user')
327 db_config
['password'] = self
.config
.get('of_password')
329 # create connector to the openflow controller
330 # load other parameters starting by of_ from config dict in a temporal dict
332 of_conn
= self
._load
_of
_module
(db_config
)
333 # create openflow thread
334 self
._create
_ofc
_task
("Default", db_config
['dpid'], of_conn
)
336 def _load_of_module(self
, db_config
):
338 import python module for each SDN controller supported
339 :param db_config: SDN dn information
343 raise ovimException("No module found it", HTTP_Internal_Server_Error
)
348 if self
.of_test_mode
:
349 return openflow_conn
.OfTestConnector({"name": db_config
['type'],
350 "dpid": db_config
['dpid'],
351 "of_debug": self
.config
['log_level_of']})
355 temp_dict
['of_ip'] = db_config
['ip']
356 temp_dict
['of_port'] = db_config
['port']
357 temp_dict
['of_dpid'] = db_config
['dpid']
358 temp_dict
['of_controller'] = db_config
['type']
359 temp_dict
['of_user'] = db_config
['user']
360 temp_dict
['of_password'] = db_config
['password']
362 temp_dict
['of_debug'] = self
.config
['log_level_of']
364 if temp_dict
['of_controller'] == 'opendaylight':
367 module
= temp_dict
['of_controller']
369 if module
not in ovim
.of_module
:
370 module_info
= imp
.find_module(module
)
371 of_conn_module
= imp
.load_module("OF_conn", *module_info
)
372 ovim
.of_module
[module
] = of_conn_module
374 of_conn_module
= ovim
.of_module
[module
]
377 return of_conn_module
.OF_conn(temp_dict
)
378 except Exception as e
:
379 self
.logger
.error("Cannot open the Openflow controller '%s': %s", type(e
).__name
__, str(e
))
380 if module_info
and module_info
[0]:
381 file.close(module_info
[0])
382 raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e
).__name
__, str(e
)),
383 HTTP_Internal_Server_Error
)
384 except (IOError, ImportError) as e
:
385 if module_info
and module_info
[0]:
386 file.close(module_info
[0])
387 self
.logger
.error("Cannot open openflow controller module '%s'; %s: %s; revise 'of_controller' "
388 "field of configuration file.", module
, type(e
).__name
__, str(e
))
389 raise ovimException("Cannot open openflow controller module '{}'; {}: {}; revise 'of_controller' "
390 "field of configuration file.".format(module
, type(e
).__name
__, str(e
)),
391 HTTP_Internal_Server_Error
)
393 def _create_ofc_thread(self
, of_conn
, ofc_uuid
="Default"):
395 Create and launch a of thread
398 # create openflow thread
400 #if 'of_controller_nets_with_same_vlan' in self.config:
401 # ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
403 # ofc_net_same_vlan = False
404 ofc_net_same_vlan
= False
406 thread
= oft
.openflow_thread(ofc_uuid
, of_conn
, of_test
=self
.of_test_mode
, db
=self
.db_of
, db_lock
=self
.db_lock
,
407 pmp_with_same_vlan
=ofc_net_same_vlan
, debug
=self
.config
['log_level_of'])
408 #r, c = thread.OF_connector.obtain_port_correspondence()
410 # raise ovimException("Cannot get openflow information %s", c)
414 def stop_service(self
):
415 threads
= self
.config
.get('host_threads', {})
416 if 'of_thread' in self
.config
:
417 threads
['of'] = (self
.config
['of_thread'])
418 if 'ofcs_thread' in self
.config
:
419 ofcs_thread
= self
.config
['ofcs_thread']
420 for ofc
in ofcs_thread
:
421 threads
[ofc
] = ofcs_thread
[ofc
]
423 if 'dhcp_thread' in self
.config
:
424 threads
['dhcp'] = (self
.config
['dhcp_thread'])
426 for thread
in threads
.values():
427 thread
.insert_task("exit")
428 for thread
in threads
.values():
431 def get_networks(self
, columns
=None, db_filter
={}, limit
=None):
433 Retreive networks available
434 :param columns: List with select query parameters
435 :param db_filter: List with where query parameters
436 :param limit: Query limit result
439 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='nets', WHERE
=db_filter
, LIMIT
=limit
)
442 raise ovimException(str(content
), -result
)
444 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
448 def show_network(self
, network_id
, db_filter
={}):
450 Get network from DB by id
451 :param network_id: net Id
452 :param db_filter: List with where query parameters
457 raise ovimException("Not network id was not found")
458 db_filter
['uuid'] = network_id
460 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
=db_filter
, LIMIT
=100)
463 raise ovimException(str(content
), -result
)
465 raise ovimException("show_network network '%s' not found" % network_id
, -result
)
467 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
469 result
, ports
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
470 WHERE
={'net_id': network_id
}, LIMIT
=100)
472 content
[0]['ports'] = ports
474 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
477 def new_network(self
, network
):
482 tenant_id
= network
.get('tenant_id')
485 result
, _
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
, "enabled": True})
487 raise ovimException("set_network error, no tenant founded", -result
)
491 net_provider
= network
.get('provider')
492 net_type
= network
.get('type')
493 net_vlan
= network
.get("vlan")
494 net_bind_net
= network
.get("bind_net")
495 net_bind_type
= network
.get("bind_type")
496 name
= network
["name"]
498 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
499 vlan_index
= name
.rfind(":")
500 if not net_bind_net
and not net_bind_type
and vlan_index
> 1:
502 vlan_tag
= int(name
[vlan_index
+ 1:])
503 if not vlan_tag
and vlan_tag
< 4096:
504 net_bind_net
= name
[:vlan_index
]
505 net_bind_type
= "vlan:" + name
[vlan_index
+ 1:]
510 # look for a valid net
511 if self
._check
_valid
_uuid
(net_bind_net
):
512 net_bind_key
= "uuid"
514 net_bind_key
= "name"
515 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
517 raise ovimException(' getting nets from db ' + content
, HTTP_Internal_Server_Error
)
519 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
521 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
522 network
["bind_net"] = content
[0]["uuid"]
525 if net_bind_type
[0:5] != "vlan:":
526 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
527 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
528 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
530 network
["bind_type"] = net_bind_type
533 if net_provider
[:9] == "openflow:":
535 if net_type
!= "ptp" and net_type
!= "data":
536 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
542 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
543 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
544 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
546 net_type
= 'bridge_man'
549 net_type
= 'bridge_man'
552 if net_provider
[:7] == 'bridge:':
553 # check it is one of the pre-provisioned bridges
554 bridge_net_name
= net_provider
[7:]
555 for brnet
in self
.config
['bridge_nets']:
556 if brnet
[0] == bridge_net_name
: # free
558 raise ovimException("invalid 'provider:physical', "
559 "bridge '%s' is already used" % bridge_net_name
, HTTP_Conflict
)
563 # if bridge_net==None:
564 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
565 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
568 elif self
.config
['network_type'] == 'bridge' and (net_type
== 'bridge_data' or net_type
== 'bridge_man'):
569 # look for a free precreated nets
570 for brnet
in self
.config
['bridge_nets']:
571 if not brnet
[3]: # free
573 if net_type
== 'bridge_man': # look for the smaller speed
574 if brnet
[2] < bridge_net
[2]:
576 else: # look for the larger speed
577 if brnet
[2] > bridge_net
[2]:
583 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
584 "will overcome this limit", HTTP_Bad_Request
)
586 self
.logger
.debug("using net " + bridge_net
)
587 net_provider
= "bridge:" + bridge_net
[0]
588 net_vlan
= bridge_net
[1]
589 elif net_type
== 'bridge_data' or net_type
== 'bridge_man' and self
.config
['network_type'] == 'ovs':
591 if not net_vlan
and (net_type
== "data" or net_type
== "ptp" or net_provider
== "OVS"):
592 net_vlan
= self
.db
.get_free_net_vlan()
594 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error
)
595 if net_provider
== 'OVS':
596 net_provider
= 'OVS' + ":" + str(net_vlan
)
598 network
['provider'] = net_provider
599 network
['type'] = net_type
600 network
['vlan'] = net_vlan
601 dhcp_integrity
= True
602 if 'enable_dhcp' in network
and network
['enable_dhcp']:
603 dhcp_integrity
= self
._check
_dhcp
_data
_integrity
(network
)
605 result
, content
= self
.db
.new_row('nets', network
, True, True)
607 if result
>= 0 and dhcp_integrity
:
609 bridge_net
[3] = content
610 if self
.config
.get("dhcp_server") and self
.config
['network_type'] == 'bridge':
611 if network
["name"] in self
.config
["dhcp_server"].get("nets", ()):
612 self
.config
["dhcp_nets"].append(content
)
613 self
.logger
.debug("dhcp_server: add new net", content
)
614 elif not bridge_net
and bridge_net
[0] in self
.config
["dhcp_server"].get("bridge_ifaces", ()):
615 self
.config
["dhcp_nets"].append(content
)
616 self
.logger
.debug("dhcp_server: add new net", content
, content
)
619 raise ovimException("Error posting network", HTTP_Internal_Server_Error
)
620 # TODO kei change update->edit
622 def edit_network(self
, network_id
, network
):
624 Update entwork data byt id
627 # Look for the previous data
628 where_
= {'uuid': network_id
}
629 result
, network_old
= self
.db
.get_table(FROM
='nets', WHERE
=where_
)
631 raise ovimException("Error updating network %s" % network_old
, HTTP_Internal_Server_Error
)
633 raise ovimException('network %s not found' % network_id
, HTTP_Not_Found
)
635 nbports
, content
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
636 WHERE
={'net_id': network_id
}, LIMIT
=100)
638 raise ovimException("http_put_network_id error %d %s" % (result
, network_old
), HTTP_Internal_Server_Error
)
640 if 'type' in network
and network
['type'] != network_old
[0]['type']:
641 raise ovimException("Can not change type of network while having ports attached",
642 HTTP_Method_Not_Allowed
)
643 if 'vlan' in network
and network
['vlan'] != network_old
[0]['vlan']:
644 raise ovimException("Can not change vlan of network while having ports attached",
645 HTTP_Method_Not_Allowed
)
648 net_provider
= network
.get('provider', network_old
[0]['provider'])
649 net_type
= network
.get('type', network_old
[0]['type'])
650 net_bind_net
= network
.get("bind_net")
651 net_bind_type
= network
.get("bind_type")
653 # look for a valid net
654 if self
._check
_valid
_uuid
(net_bind_net
):
655 net_bind_key
= "uuid"
657 net_bind_key
= "name"
658 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
660 raise ovimException('Getting nets from db ' + content
, HTTP_Internal_Server_Error
)
662 raise ovimException("bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
664 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
),
666 network
["bind_net"] = content
[0]["uuid"]
668 if net_bind_type
[0:5] != "vlan:":
669 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
670 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
671 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
674 if net_provider
[:9] == "openflow:":
675 if net_type
!= "ptp" and net_type
!= "data":
676 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request
)
678 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
679 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
680 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
682 # insert in data base
683 result
, content
= self
.db
.update_rows('nets', network
, WHERE
={'uuid': network_id
}, log
=True)
685 # if result > 0 and nbports>0 and 'admin_state_up' in network
686 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
691 self
.net_update_ofc_thread(network_id
)
692 except ovimException
as e
:
693 raise ovimException("Error while launching openflow rules in network '{}' {}"
694 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
695 except Exception as e
:
696 raise ovimException("Error while launching openflow rules in network '{}' {}"
697 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
699 if self
.config
.get("dhcp_server"):
700 if network_id
in self
.config
["dhcp_nets"]:
701 self
.config
["dhcp_nets"].remove(network_id
)
702 if network
.get("name", network_old
[0]["name"]) in self
.config
["dhcp_server"].get("nets", ()):
703 self
.config
["dhcp_nets"].append(network_id
)
705 net_bind
= network
.get("bind_type", network_old
[0]["bind_type"])
706 if net_bind
and net_bind
and net_bind
[:7] == "bridge:" and net_bind
[7:] in self
.config
["dhcp_server"].get(
707 "bridge_ifaces", ()):
708 self
.config
["dhcp_nets"].append(network_id
)
711 raise ovimException(content
, -result
)
713 def delete_network(self
, network_id
):
715 Delete network by network id
716 :param network_id: network id
720 # delete from the data base
721 result
, content
= self
.db
.delete_row('nets', network_id
)
724 raise ovimException("Network %s not found " % network_id
, HTTP_Not_Found
)
726 for brnet
in self
.config
['bridge_nets']:
727 if brnet
[3] == network_id
:
730 if self
.config
.get("dhcp_server") and network_id
in self
.config
["dhcp_nets"]:
731 self
.config
["dhcp_nets"].remove(network_id
)
734 raise ovimException("Error deleting network %s" % network_id
, HTTP_Internal_Server_Error
)
736 def get_openflow_rules(self
, network_id
=None):
738 Get openflow id from DB
739 :param network_id: Network id, if none all networks will be retrieved
740 :return: Return a list with Openflow rules per net
746 where_
= {"net_id": network_id
}
747 result
, content
= self
.db
.get_table(
748 SELECT
=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
749 WHERE
=where_
, FROM
='of_flows')
752 raise ovimException(str(content
), -result
)
755 def edit_openflow_rules(self
, network_id
=None):
758 To make actions over the net. The action is to reinstall the openflow rules
759 network_id can be 'all'
760 :param network_id: Network id, if none all networks will be retrieved
761 :return : Number of nets updated
768 where_
= {"uuid": network_id
}
769 result
, content
= self
.db
.get_table(SELECT
=("uuid", "type"), WHERE
=where_
, FROM
='nets')
772 raise ovimException(str(content
), -result
)
775 if net
["type"] != "ptp" and net
["type"] != "data":
780 self
.net_update_ofc_thread(net
['uuid'])
781 except ovimException
as e
:
782 raise ovimException("Error updating network'{}' {}".format(net
['uuid'], str(e
)),
783 HTTP_Internal_Server_Error
)
784 except Exception as e
:
785 raise ovimException("Error updating network '{}' {}".format(net
['uuid'], str(e
)),
786 HTTP_Internal_Server_Error
)
790 def delete_openflow_rules(self
, ofc_id
=None):
792 To make actions over the net. The action is to delete ALL openflow rules
793 :return: return operation result
797 if 'Default' in self
.config
['ofcs_thread']:
798 r
, c
= self
.config
['ofcs_thread']['Default'].insert_task("clear-all")
800 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
802 elif ofc_id
in self
.config
['ofcs_thread']:
803 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("clear-all")
807 raise ovimException(str(c
), -r
)
809 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
812 def get_openflow_ports(self
, ofc_id
=None):
814 Obtain switch ports names of openflow controller
815 :return: Return flow ports in DB
818 if 'Default' in self
.config
['ofcs_thread']:
819 conn
= self
.config
['ofcs_thread']['Default'].OF_connector
821 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
823 if ofc_id
in self
.config
['ofcs_thread']:
824 conn
= self
.config
['ofcs_thread'][ofc_id
].OF_connector
826 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
829 def get_ports(self
, columns
=None, filter={}, limit
=None):
830 # result, content = my.db.get_ports(where_)
831 result
, content
= self
.db
.get_table(SELECT
=columns
, WHERE
=filter, FROM
='ports', LIMIT
=limit
)
833 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
834 raise ovimException(str(content
), -result
)
836 convert_boolean(content
, ('admin_state_up',))
839 def new_port(self
, port_data
):
840 port_data
['type'] = 'external'
841 if port_data
.get('net_id'):
842 # check that new net has the correct type
843 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
845 raise ovimException(str(new_net
), -result
)
846 # insert in data base
847 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
849 if 'net_id' in port_data
:
851 self
.net_update_ofc_thread(port_data
['net_id'])
852 except ovimException
as e
:
853 raise ovimException("Cannot insert a task for updating network '{}' {}"
854 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
855 except Exception as e
:
856 raise ovimException("Cannot insert a task for updating network '{}' {}"
857 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
861 raise ovimException(str(uuid
), -result
)
863 def new_external_port(self
, port_data
):
865 Create new external port and check port mapping correspondence
866 :param port_data: port_data = {
867 'region': 'datacenter region',
868 'compute_node': 'compute node id',
869 'pci': 'pci port address',
872 'tenant_id': 'tenant id',
875 'ip_address': 'ip address - optional'}
879 port_data
['type'] = 'external'
881 if port_data
.get('net_id'):
882 # check that new net has the correct type
883 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
885 raise ovimException(str(new_net
), -result
)
886 # insert in data base
889 if port_data
.get('region'):
890 db_filter
['region'] = port_data
['region']
891 if port_data
.get('pci'):
892 db_filter
['pci'] = port_data
['pci']
893 if port_data
.get('compute_node'):
894 db_filter
['compute_node'] = port_data
['compute_node']
896 columns
= ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
897 port_mapping_data
= self
.get_of_port_mappings(columns
, db_filter
)
899 if not len(port_mapping_data
):
900 raise ovimException("No port mapping founded for '{}'".format(str(db_filter
)),
902 elif len(port_mapping_data
) > 1:
903 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
906 port_data
['ofc_id'] = port_mapping_data
[0]['ofc_id']
907 port_data
['switch_dpid'] = port_mapping_data
[0]['switch_dpid']
908 port_data
['switch_port'] = port_mapping_data
[0]['switch_port']
909 port_data
['switch_mac'] = port_mapping_data
[0]['switch_mac']
911 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
912 if 'region' in port_data
:
913 del port_data
['region']
914 if 'pci' in port_data
:
916 if 'compute_node' in port_data
:
917 del port_data
['compute_node']
919 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
922 self
.net_update_ofc_thread(port_data
['net_id'], port_data
['ofc_id'])
923 except ovimException
as e
:
924 raise ovimException("Cannot insert a task for updating network '{}' {}".
925 format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
926 except Exception as e
:
927 raise ovimException("Cannot insert a task for updating network '{}' {}"
928 .format(port_data
['net_id'], e
), HTTP_Internal_Server_Error
)
931 raise ovimException(str(uuid
), -result
)
933 def net_update_ofc_thread(self
, net_id
, ofc_id
=None, switch_dpid
=None):
935 Insert a update net task by net id or ofc_id for each ofc thread
936 :param net_id: network id
937 :param ofc_id: openflow controller id
938 :param switch_dpid: switch dpid
942 raise ovimException("No net_id received", HTTP_Internal_Server_Error
)
945 c
= 'No valid ofc_id or switch_dpid received'
948 ports
= self
.get_ports(filter={"net_id": net_id
})
950 port_ofc_id
= port
.get('ofc_id', None)
952 ofc_id
= port
['ofc_id']
953 switch_dpid
= port
['switch_dpid']
955 #TODO if not ofc_id: look at database table ofcs
958 # If no ofc_id found it, default ofc_id is used.
959 if not ofc_id
and not switch_dpid
:
962 if ofc_id
and ofc_id
in self
.config
['ofcs_thread']:
963 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("update-net", net_id
)
966 ofcs_dpid_list
= self
.config
['ofcs_thread_dpid']
967 for ofc_t
in ofcs_dpid_list
:
968 if switch_dpid
in ofc_t
:
969 r
, c
= ofc_t
[switch_dpid
].insert_task("update-net", net_id
)
972 message
= "Cannot insert a task for updating network '{}', {}".format(net_id
, c
)
973 self
.logger
.error(message
)
974 raise ovimException(message
, HTTP_Internal_Server_Error
)
976 def delete_port(self
, port_id
):
977 # Look for the previous port data
978 result
, ports
= self
.db
.get_table(WHERE
={'uuid': port_id
, "type": "external"}, FROM
='ports')
980 raise ovimException("Cannot get port info from database: {}".format(ports
), http_code
=-result
)
981 # delete from the data base
982 result
, content
= self
.db
.delete_row('ports', port_id
)
984 raise ovimException("External port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
986 raise ovimException("Cannot delete port from database: {}".format(content
), http_code
=-result
)
988 network
= ports
[0].get('net_id', None)
993 self
.net_update_ofc_thread(network
, ofc_id
=ports
[0]["ofc_id"], switch_dpid
=ports
[0]["switch_dpid"])
994 except ovimException
as e
:
995 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network
, str(e
)),
996 HTTP_Internal_Server_Error
)
997 except Exception as e
:
998 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network
, str(e
)),
999 HTTP_Internal_Server_Error
)
1003 def edit_port(self
, port_id
, port_data
, admin
=True):
1004 # Look for the previous port data
1005 result
, content
= self
.db
.get_table(FROM
="ports", WHERE
={'uuid': port_id
})
1007 raise ovimException("Cannot get port info from database: {}".format(content
), http_code
=-result
)
1009 raise ovimException("Port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1014 if 'net_id' in port_data
:
1016 old_net
= port
.get('net_id', None)
1017 new_net
= port_data
['net_id']
1018 if old_net
!= new_net
:
1021 nets
.append(new_net
) # put first the new net, so that new openflow rules are created before removing the old ones
1023 nets
.append(old_net
)
1024 if port
['type'] == 'instance:bridge' or port
['type'] == 'instance:ovs':
1025 raise ovimException("bridge interfaces cannot be attached to a different net", http_code
=HTTP_Forbidden
)
1026 elif port
['type'] == 'external' and not admin
:
1027 raise ovimException("Needed admin privileges",http_code
=HTTP_Unauthorized
)
1029 # check that new net has the correct type
1030 result
, new_net_dict
= self
.db
.check_target_net(new_net
, None, port
['type'])
1032 raise ovimException("Error {}".format(new_net_dict
), http_code
=HTTP_Conflict
)
1033 # change VLAN for SR-IOV ports
1034 if result
>= 0 and port
["type"] == "instance:data" and port
["model"] == "VF": # TODO consider also VFnotShared
1036 port_data
["vlan"] = None
1038 port_data
["vlan"] = new_net_dict
["vlan"]
1039 # get host where this VM is allocated
1040 result
, content
= self
.db
.get_table(FROM
="instances", WHERE
={"uuid": port
["instance_id"]})
1042 host_id
= content
[0]["host_id"]
1044 # insert in data base
1046 result
, content
= self
.db
.update_rows('ports', port_data
, WHERE
={'uuid': port_id
}, log
=False)
1047 port
.update(port_data
)
1049 # Insert task to complete actions
1053 self
.net_update_ofc_thread(net_id
, port
["ofc_id"], switch_dpid
=port
["switch_dpid"])
1054 except ovimException
as e
:
1055 raise ovimException("Error updating network'{}' {}".format(net_id
, str(e
)),
1056 HTTP_Internal_Server_Error
)
1057 except Exception as e
:
1058 raise ovimException("Error updating network '{}' {}".format(net_id
, str(e
)),
1059 HTTP_Internal_Server_Error
)
1062 r
, v
= self
.config
['host_threads'][host_id
].insert_task("edit-iface", port_id
, old_net
, new_net
)
1064 self
.logger
.error("Error updating network '{}' {}".format(r
,v
))
1065 # TODO Do something if fails
1069 raise ovimException("Error {}".format(content
), http_code
=-result
)
1071 def new_of_controller(self
, ofc_data
):
1073 Create a new openflow controller into DB
1074 :param ofc_data: Dict openflow controller data
1075 :return: openflow controller dpid
1078 result
, ofc_uuid
= self
.db
.new_row('ofcs', ofc_data
, True, True)
1080 raise ovimException("New ofc Error %s" % ofc_uuid
, HTTP_Internal_Server_Error
)
1082 ofc_data
['uuid'] = ofc_uuid
1083 of_conn
= self
._load
_of
_module
(ofc_data
)
1084 self
._create
_ofc
_task
(ofc_uuid
, ofc_data
['dpid'], of_conn
)
1088 def edit_of_controller(self
, of_id
, ofc_data
):
1090 Edit an openflow controller entry from DB
1094 raise ovimException("No data received during uptade OF contorller", http_code
=HTTP_Internal_Server_Error
)
1096 old_of_controller
= self
.show_of_controller(of_id
)
1098 if old_of_controller
:
1099 result
, content
= self
.db
.update_rows('ofcs', ofc_data
, WHERE
={'uuid': of_id
}, log
=False)
1103 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1106 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1107 http_code
=HTTP_Internal_Server_Error
)
1109 def delete_of_controller(self
, of_id
):
1111 Delete an openflow controller from DB.
1112 :param of_id: openflow controller dpid
1116 ofc
= self
.show_of_controller(of_id
)
1118 result
, content
= self
.db
.delete_row("ofcs", of_id
)
1120 raise ovimException("Cannot delete ofc from database: {}".format(content
), http_code
=-result
)
1122 raise ovimException("ofc {} not found ".format(content
), http_code
=HTTP_Not_Found
)
1124 ofc_thread
= self
.config
['ofcs_thread'][of_id
]
1125 del self
.config
['ofcs_thread'][of_id
]
1126 for ofc_th
in self
.config
['ofcs_thread_dpid']:
1127 if ofc
['dpid'] in ofc_th
:
1128 self
.config
['ofcs_thread_dpid'].remove(ofc_th
)
1130 ofc_thread
.insert_task("exit")
1135 def show_of_controller(self
, uuid
):
1137 Show an openflow controller by dpid from DB.
1138 :param db_filter: List with where query parameters
1142 result
, content
= self
.db
.get_table(FROM
='ofcs', WHERE
={"uuid": uuid
}, LIMIT
=100)
1145 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid
),
1146 http_code
=HTTP_Not_Found
)
1148 raise ovimException("Openflow controller with uuid '{}' error".format(uuid
),
1149 http_code
=HTTP_Internal_Server_Error
)
1152 def get_of_controllers(self
, columns
=None, db_filter
={}, limit
=None):
1154 Show an openflow controllers from DB.
1155 :param columns: List with SELECT query parameters
1156 :param db_filter: List with where query parameters
1157 :param limit: result Limit
1160 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='ofcs', WHERE
=db_filter
, LIMIT
=limit
)
1163 raise ovimException(str(content
), -result
)
1167 def get_tenants(self
, columns
=None, db_filter
={}, limit
=None):
1169 Retrieve tenant list from DB
1170 :param columns: List with SELECT query parameters
1171 :param db_filter: List with where query parameters
1172 :param limit: result limit
1175 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=columns
, WHERE
=db_filter
, LIMIT
=limit
)
1177 raise ovimException('get_tenatns Error {}'.format(str(content
)), -result
)
1179 convert_boolean(content
, ('enabled',))
1182 def show_tenant_id(self
, tenant_id
):
1184 Get tenant from DB by id
1185 :param tenant_id: tenant id
1188 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid', 'name', 'description', 'enabled'),
1189 WHERE
={"uuid": tenant_id
})
1191 raise ovimException(str(content
), -result
)
1193 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1195 convert_boolean(content
, ('enabled',))
1198 def new_tentant(self
, tenant
):
1200 Create a tenant and store in DB
1201 :param tenant: Dictionary with tenant data
1202 :return: the uuid of created tenant. Raise exception upon error
1205 # insert in data base
1206 result
, tenant_uuid
= self
.db
.new_tenant(tenant
)
1211 raise ovimException(str(tenant_uuid
), -result
)
1213 def delete_tentant(self
, tenant_id
):
1215 Delete a tenant from the database.
1216 :param tenant_id: Tenant id
1217 :return: delete tenant id
1221 r
, tenants_flavors
= self
.db
.get_table(FROM
='tenants_flavors', SELECT
=('flavor_id', 'tenant_id'),
1222 WHERE
={'tenant_id': tenant_id
})
1224 tenants_flavors
= ()
1225 r
, tenants_images
= self
.db
.get_table(FROM
='tenants_images', SELECT
=('image_id', 'tenant_id'),
1226 WHERE
={'tenant_id': tenant_id
})
1230 result
, content
= self
.db
.delete_row('tenants', tenant_id
)
1232 raise ovimException("tenant '%s' not found" % tenant_id
, HTTP_Not_Found
)
1234 for flavor
in tenants_flavors
:
1235 self
.db
.delete_row_by_key("flavors", "uuid", flavor
['flavor_id'])
1236 for image
in tenants_images
:
1237 self
.db
.delete_row_by_key("images", "uuid", image
['image_id'])
1240 raise ovimException("Error deleting tenant '%s' " % tenant_id
, HTTP_Internal_Server_Error
)
1242 def edit_tenant(self
, tenant_id
, tenant_data
):
1244 Update a tenant data identified by tenant id
1245 :param tenant_id: tenant id
1246 :param tenant_data: Dictionary with tenant data
1250 # Look for the previous data
1251 result
, tenant_data_old
= self
.db
.get_table(FROM
='tenants', WHERE
={'uuid': tenant_id
})
1253 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id
, tenant_data_old
),
1254 HTTP_Internal_Server_Error
)
1256 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1258 # insert in data base
1259 result
, content
= self
.db
.update_rows('tenants', tenant_data
, WHERE
={'uuid': tenant_id
}, log
=True)
1263 raise ovimException(str(content
), -result
)
1265 def set_of_port_mapping(self
, of_maps
, ofc_id
=None, switch_dpid
=None, region
=None):
1267 Create new port mapping entry
1268 :param of_maps: List with port mapping information
1269 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1270 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1271 :param ofc_id: ofc id
1272 :param switch_dpid: switch dpid
1273 :param region: datacenter region id
1279 map['ofc_id'] = ofc_id
1281 map['switch_dpid'] = switch_dpid
1283 map['region'] = region
1285 for of_map
in of_maps
:
1286 result
, uuid
= self
.db
.new_row('of_port_mappings', of_map
, True)
1288 of_map
["uuid"] = uuid
1290 raise ovimException(str(uuid
), -result
)
1293 def clear_of_port_mapping(self
, db_filter
={}):
1295 Clear port mapping filtering using db_filter dict
1296 :param db_filter: Parameter to filter during remove process
1299 result
, content
= self
.db
.delete_row_by_dict(FROM
='of_port_mappings', WHERE
=db_filter
)
1304 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter
)),
1305 HTTP_Internal_Server_Error
)
1307 def get_of_port_mappings(self
, column
=None, db_filter
=None, db_limit
=None):
1309 Retrive port mapping from DB
1314 result
, content
= self
.db
.get_table(SELECT
=column
, WHERE
=db_filter
, FROM
='of_port_mappings', LIMIT
=db_limit
)
1317 self
.logger
.error("get_of_port_mappings Error %d %s", result
, content
)
1318 raise ovimException(str(content
), -result
)
1322 def get_dhcp_controller(self
):
1324 Create an host_thread object for manage openvim controller and not create a thread for itself
1325 :return: dhcp_host openvim controller object
1328 if 'openvim_controller' in self
.config
['host_threads']:
1329 return self
.config
['host_threads']['openvim_controller']
1332 controller_ip
= self
.config
['ovs_controller_ip']
1333 ovs_controller_user
= self
.config
['ovs_controller_user']
1335 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
1336 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
1338 dhcp_host
= ht
.host_thread(name
='openvim_controller', user
=ovs_controller_user
, host
=controller_ip
,
1340 db_lock
=self
.db_lock
, test
=host_test_mode
,
1341 image_path
=self
.config
['image_path'], version
=self
.config
['version'],
1342 host_id
='openvim_controller', develop_mode
=host_develop_mode
,
1343 develop_bridge_iface
=bridge_ifaces
)
1345 self
.config
['host_threads']['openvim_controller'] = dhcp_host
1346 if not host_test_mode
:
1347 dhcp_host
.ssh_connect()
1350 def launch_dhcp_server(self
, vlan
, first_ip
, last_ip
, cidr
, gateway
):
1352 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1353 :param vlan: vlan identifier
1354 :param first_ip: First dhcp range ip
1355 :param last_ip: Last dhcp range ip
1356 :param cidr: net cidr
1357 :param gateway: net gateway
1360 ip_tools
= IPNetwork(cidr
)
1361 dhcp_netmask
= str(ip_tools
.netmask
)
1362 ip_range
= [first_ip
, last_ip
]
1364 dhcp_path
= self
.config
['ovs_controller_file_path']
1366 controller_host
= self
.get_dhcp_controller()
1367 controller_host
.create_linux_bridge(vlan
)
1368 controller_host
.create_dhcp_interfaces(vlan
, first_ip
, dhcp_netmask
)
1369 controller_host
.launch_dhcp_server(vlan
, ip_range
, dhcp_netmask
, dhcp_path
, gateway
)
1371 if __name__
== "__main__":
1373 parser
= argparse
.ArgumentParser()
1374 parser
.add_argument("-v","--version", help="show ovim library version", action
="store_true")
1375 parser
.add_argument("--database-version", help="show required database version", action
="store_true")
1376 args
= parser
.parse_args()
1378 print ('openvimd version {} {}'.format(ovim
.get_version(), ovim
.get_version_date()))
1379 print ('(c) Copyright Telefonica')
1380 elif args
.database_version
:
1381 print ('required database version: {}'.format(ovim
.get_database_version()))