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.8-r524"
33 version_date
= "March 2017"
34 database_version
= "0.15" #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
= logging
.getLogger(configuration
["logger_name"])
100 self
.db
= self
._create
_database
_connection
()
103 self
.of_test_mode
= False
105 def _create_database_connection(self
):
106 db
= vim_db
.vim_db((self
.config
["network_vlan_range_start"], self
.config
["network_vlan_range_end"]),
107 self
.config
['log_level_db']);
108 if db
.connect(self
.config
['db_host'], self
.config
['db_user'], self
.config
['db_passwd'],
109 self
.config
['db_name']) == -1:
110 # self.logger.error("Cannot connect to database %s at %s@%s", self.config['db_name'], self.config['db_user'],
111 # self.config['db_host'])
112 raise ovimException("Cannot connect to database {} at {}@{}".format(self
.config
['db_name'],
113 self
.config
['db_user'],
114 self
.config
['db_host']) )
122 def get_version_date():
126 def get_database_version():
127 return database_version
130 def _check_dhcp_data_integrity(network
):
132 Check if all dhcp parameter for anet are valid, if not will be calculated from cidr value
133 :param network: list with user nets paramters
136 if "cidr" in network
:
137 cidr
= network
["cidr"]
138 ip_tools
= IPNetwork(cidr
)
139 cidr_len
= ip_tools
.prefixlen
143 ips
= IPNetwork(cidr
)
144 if "dhcp_first_ip" not in network
:
145 network
["dhcp_first_ip"] = str(ips
[2])
146 if "dhcp_last_ip" not in network
:
147 network
["dhcp_last_ip"] = str(ips
[-2])
148 if "gateway_ip" not in network
:
149 network
["gateway_ip"] = str(ips
[1])
156 def _check_valid_uuid(uuid
):
157 id_schema
= {"type": "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
159 js_v(uuid
, id_schema
)
161 except js_e
.ValidationError
:
164 def start_service(self
):
169 global database_version
170 # if self.running_info:
171 # return #TODO service can be checked and rebuild broken threads
172 r
= self
.db
.get_db_version()
174 raise ovimException("DATABASE is not a VIM one or it is a '0.0' version. Try to upgrade to version '{}' with "\
175 "'./database_utils/migrate_vim_db.sh'".format(database_version
) )
176 elif r
[1] != database_version
:
177 raise ovimException("DATABASE wrong version '{}'. Try to upgrade/downgrade to version '{}' with "\
178 "'./database_utils/migrate_vim_db.sh'".format(r
[1], database_version
) )
180 # create database connection for openflow threads
181 self
.db_of
= self
._create
_database
_connection
()
182 self
.config
["db"] = self
.db_of
183 self
.db_lock
= threading
.Lock()
184 self
.config
["db_lock"] = self
.db_lock
186 self
.of_test_mode
= False if self
.config
['mode'] == 'normal' or self
.config
['mode'] == "OF only" else True
187 # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge,
190 self
.config
['dhcp_nets'] = []
191 self
.config
['bridge_nets'] = []
192 for bridge
, vlan_speed
in self
.config
["bridge_ifaces"].items():
193 # skip 'development_bridge'
194 if self
.config
['mode'] == 'development' and self
.config
['development_bridge'] == bridge
:
196 self
.config
['bridge_nets'].append([bridge
, vlan_speed
[0], vlan_speed
[1], None])
198 # check if this bridge is already used (present at database) for a network)
199 used_bridge_nets
= []
200 for brnet
in self
.config
['bridge_nets']:
201 r
, nets
= self
.db
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'provider': "bridge:" + brnet
[0]})
203 brnet
[3] = nets
[0]['uuid']
204 used_bridge_nets
.append(brnet
[0])
205 if self
.config
.get("dhcp_server"):
206 if brnet
[0] in self
.config
["dhcp_server"]["bridge_ifaces"]:
207 self
.config
['dhcp_nets'].append(nets
[0]['uuid'])
208 if len(used_bridge_nets
) > 0:
209 self
.logger
.info("found used bridge nets: " + ",".join(used_bridge_nets
))
210 # get nets used by dhcp
211 if self
.config
.get("dhcp_server"):
212 for net
in self
.config
["dhcp_server"].get("nets", ()):
213 r
, nets
= self
.db
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'name': net
})
215 self
.config
['dhcp_nets'].append(nets
[0]['uuid'])
218 self
._start
_ofc
_default
_task
()
220 # OFC per tenant in DB
221 self
._start
_of
_db
_tasks
()
223 # create dhcp_server thread
224 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
225 dhcp_params
= self
.config
.get("dhcp_server")
227 thread
= dt
.dhcp_thread(dhcp_params
=dhcp_params
, test
=host_test_mode
, dhcp_nets
=self
.config
["dhcp_nets"],
228 db
=self
.db_of
, db_lock
=self
.db_lock
, debug
=self
.config
['log_level_of'])
230 self
.config
['dhcp_thread'] = thread
232 # Create one thread for each host
233 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
234 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
235 host_develop_bridge_iface
= self
.config
.get('development_bridge', None)
237 # get host list from data base before starting threads
238 r
, hosts
= self
.db
.get_table(SELECT
=('name', 'ip_name', 'user', 'uuid'), FROM
='hosts', WHERE
={'status': 'ok'})
240 raise ovimException("Cannot get hosts from database {}".format(hosts
))
242 self
.config
['host_threads'] = {}
244 host
['image_path'] = '/opt/VNF/images/openvim'
245 thread
= ht
.host_thread(name
=host
['name'], user
=host
['user'], host
=host
['ip_name'], db
=self
.db_of
,
246 db_lock
=self
.db_lock
, test
=host_test_mode
, image_path
=self
.config
['image_path'],
247 version
=self
.config
['version'], host_id
=host
['uuid'], develop_mode
=host_develop_mode
,
248 develop_bridge_iface
=host_develop_bridge_iface
)
250 self
.config
['host_threads'][host
['uuid']] = thread
252 # create ovs dhcp thread
253 result
, content
= self
.db
.get_table(FROM
='nets')
255 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
256 raise ovimException(str(content
), -result
)
259 net_type
= net
['type']
260 if (net_type
== 'bridge_data' or net_type
== 'bridge_man') \
261 and net
["provider"][:4] == 'OVS:' and net
["enable_dhcp"] == "true":
262 self
.launch_dhcp_server(net
['vlan'],
263 net
['dhcp_first_ip'],
268 def _start_of_db_tasks(self
):
270 Start ofc task for existing ofcs in database
275 ofcs
= self
.get_of_controllers()
278 of_conn
= self
._load
_of
_module
(ofc
)
279 # create ofc thread per of controller
280 self
._create
_ofc
_task
(ofc
['uuid'], ofc
['dpid'], of_conn
)
282 def _create_ofc_task(self
, ofc_uuid
, dpid
, of_conn
):
284 Create an ofc thread for handle each sdn controllers
285 :param ofc_uuid: sdn controller uuid
286 :param dpid: sdn controller dpid
287 :param of_conn: OF_conn module
290 if 'ofcs_thread' not in self
.config
and 'ofcs_thread_dpid' not in self
.config
:
292 ofcs_thread_dpid
= []
294 ofcs_threads
= self
.config
['ofcs_thread']
295 ofcs_thread_dpid
= self
.config
['ofcs_thread_dpid']
297 if ofc_uuid
not in ofcs_threads
:
298 ofc_thread
= self
._create
_ofc
_thread
(of_conn
, ofc_uuid
)
299 if ofc_uuid
== "Default":
300 self
.config
['of_thread'] = ofc_thread
302 ofcs_threads
[ofc_uuid
] = ofc_thread
303 self
.config
['ofcs_thread'] = ofcs_threads
305 ofcs_thread_dpid
.append({dpid
: ofc_thread
})
306 self
.config
['ofcs_thread_dpid'] = ofcs_thread_dpid
308 def _start_ofc_default_task(self
):
310 Create default ofc thread
312 if 'of_controller' not in self
.config \
313 and 'of_controller_ip' not in self
.config \
314 and 'of_controller_port' not in self
.config \
315 and 'of_controller_dpid' not in self
.config
:
320 db_config
['ip'] = self
.config
.get('of_controller_ip')
321 db_config
['port'] = self
.config
.get('of_controller_port')
322 db_config
['dpid'] = self
.config
.get('of_controller_dpid')
323 db_config
['type'] = self
.config
.get('of_controller')
324 db_config
['user'] = self
.config
.get('of_user')
325 db_config
['password'] = self
.config
.get('of_password')
327 # create connector to the openflow controller
328 # load other parameters starting by of_ from config dict in a temporal dict
330 of_conn
= self
._load
_of
_module
(db_config
)
331 # create openflow thread
332 self
._create
_ofc
_task
("Default", db_config
['dpid'], of_conn
)
334 def _load_of_module(self
, db_config
):
336 import python module for each SDN controller supported
337 :param db_config: SDN dn information
341 raise ovimException("No module found it", HTTP_Internal_Server_Error
)
346 if self
.of_test_mode
:
347 return openflow_conn
.OfTestConnector({"name": db_config
['type'],
348 "dpid": db_config
['dpid'],
349 "of_debug": self
.config
['log_level_of']})
353 temp_dict
['of_ip'] = db_config
['ip']
354 temp_dict
['of_port'] = db_config
['port']
355 temp_dict
['of_dpid'] = db_config
['dpid']
356 temp_dict
['of_controller'] = db_config
['type']
357 temp_dict
['of_user'] = db_config
['user']
358 temp_dict
['of_password'] = db_config
['password']
360 temp_dict
['of_debug'] = self
.config
['log_level_of']
362 if temp_dict
['of_controller'] == 'opendaylight':
365 module
= temp_dict
['of_controller']
367 if module
not in ovim
.of_module
:
368 module_info
= imp
.find_module(module
)
369 of_conn_module
= imp
.load_module("OF_conn", *module_info
)
370 ovim
.of_module
[module
] = of_conn_module
372 of_conn_module
= ovim
.of_module
[module
]
375 return of_conn_module
.OF_conn(temp_dict
)
376 except Exception as e
:
377 self
.logger
.error("Cannot open the Openflow controller '%s': %s", type(e
).__name
__, str(e
))
378 if module_info
and module_info
[0]:
379 file.close(module_info
[0])
380 raise ovimException("Cannot open the Openflow controller '{}': '{}'".format(type(e
).__name
__, str(e
)),
381 HTTP_Internal_Server_Error
)
382 except (IOError, ImportError) as e
:
383 if module_info
and module_info
[0]:
384 file.close(module_info
[0])
385 self
.logger
.error("Cannot open openflow controller module '%s'; %s: %s; revise 'of_controller' "
386 "field of configuration file.", module
, type(e
).__name
__, str(e
))
387 raise ovimException("Cannot open openflow controller module '{}'; {}: {}; revise 'of_controller' "
388 "field of configuration file.".format(module
, type(e
).__name
__, str(e
)),
389 HTTP_Internal_Server_Error
)
391 def _create_ofc_thread(self
, of_conn
, ofc_uuid
="Default"):
393 Create and launch a of thread
396 # create openflow thread
398 #if 'of_controller_nets_with_same_vlan' in self.config:
399 # ofc_net_same_vlan = self.config['of_controller_nets_with_same_vlan']
401 # ofc_net_same_vlan = False
402 ofc_net_same_vlan
= False
404 thread
= oft
.openflow_thread(ofc_uuid
, of_conn
, of_test
=self
.of_test_mode
, db
=self
.db_of
, db_lock
=self
.db_lock
,
405 pmp_with_same_vlan
=ofc_net_same_vlan
, debug
=self
.config
['log_level_of'])
406 #r, c = thread.OF_connector.obtain_port_correspondence()
408 # raise ovimException("Cannot get openflow information %s", c)
412 def stop_service(self
):
413 threads
= self
.config
.get('host_threads', {})
414 if 'of_thread' in self
.config
:
415 threads
['of'] = (self
.config
['of_thread'])
416 if 'ofcs_thread' in self
.config
:
417 ofcs_thread
= self
.config
['ofcs_thread']
418 for ofc
in ofcs_thread
:
419 threads
[ofc
] = ofcs_thread
[ofc
]
421 if 'dhcp_thread' in self
.config
:
422 threads
['dhcp'] = (self
.config
['dhcp_thread'])
424 for thread
in threads
.values():
425 thread
.insert_task("exit")
426 for thread
in threads
.values():
429 def get_networks(self
, columns
=None, db_filter
={}, limit
=None):
431 Retreive networks available
432 :param columns: List with select query parameters
433 :param db_filter: List with where query parameters
434 :param limit: Query limit result
437 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='nets', WHERE
=db_filter
, LIMIT
=limit
)
440 raise ovimException(str(content
), -result
)
442 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
446 def show_network(self
, network_id
, db_filter
={}):
448 Get network from DB by id
449 :param network_id: net Id
450 :param db_filter: List with where query parameters
455 raise ovimException("Not network id was not found")
456 db_filter
['uuid'] = network_id
458 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
=db_filter
, LIMIT
=100)
461 raise ovimException(str(content
), -result
)
463 raise ovimException("show_network network '%s' not found" % network_id
, -result
)
465 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
467 result
, ports
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
468 WHERE
={'net_id': network_id
}, LIMIT
=100)
470 content
[0]['ports'] = ports
472 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
475 def new_network(self
, network
):
480 tenant_id
= network
.get('tenant_id')
483 result
, _
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
, "enabled": True})
485 raise ovimException("set_network error, no tenant founded", -result
)
489 net_provider
= network
.get('provider')
490 net_type
= network
.get('type')
491 net_vlan
= network
.get("vlan")
492 net_bind_net
= network
.get("bind_net")
493 net_bind_type
= network
.get("bind_type")
494 name
= network
["name"]
496 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
497 vlan_index
= name
.rfind(":")
498 if not net_bind_net
and not net_bind_type
and vlan_index
> 1:
500 vlan_tag
= int(name
[vlan_index
+ 1:])
501 if not vlan_tag
and vlan_tag
< 4096:
502 net_bind_net
= name
[:vlan_index
]
503 net_bind_type
= "vlan:" + name
[vlan_index
+ 1:]
508 # look for a valid net
509 if self
._check
_valid
_uuid
(net_bind_net
):
510 net_bind_key
= "uuid"
512 net_bind_key
= "name"
513 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
515 raise ovimException(' getting nets from db ' + content
, HTTP_Internal_Server_Error
)
517 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
519 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
520 network
["bind_net"] = content
[0]["uuid"]
523 if net_bind_type
[0:5] != "vlan:":
524 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
525 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
526 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
528 network
["bind_type"] = net_bind_type
531 if net_provider
[:9] == "openflow:":
533 if net_type
!= "ptp" and net_type
!= "data":
534 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
540 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
541 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
542 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
544 net_type
= 'bridge_man'
547 net_type
= 'bridge_man'
550 if net_provider
[:7] == 'bridge:':
551 # check it is one of the pre-provisioned bridges
552 bridge_net_name
= net_provider
[7:]
553 for brnet
in self
.config
['bridge_nets']:
554 if brnet
[0] == bridge_net_name
: # free
556 raise ovimException("invalid 'provider:physical', "
557 "bridge '%s' is already used" % bridge_net_name
, HTTP_Conflict
)
561 # if bridge_net==None:
562 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
563 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
566 elif self
.config
['network_type'] == 'bridge' and (net_type
== 'bridge_data' or net_type
== 'bridge_man'):
567 # look for a free precreated nets
568 for brnet
in self
.config
['bridge_nets']:
569 if not brnet
[3]: # free
571 if net_type
== 'bridge_man': # look for the smaller speed
572 if brnet
[2] < bridge_net
[2]:
574 else: # look for the larger speed
575 if brnet
[2] > bridge_net
[2]:
581 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
582 "will overcome this limit", HTTP_Bad_Request
)
584 self
.logger
.debug("using net " + bridge_net
)
585 net_provider
= "bridge:" + bridge_net
[0]
586 net_vlan
= bridge_net
[1]
587 elif net_type
== 'bridge_data' or net_type
== 'bridge_man' and self
.config
['network_type'] == 'ovs':
589 if not net_vlan
and (net_type
== "data" or net_type
== "ptp" or net_provider
== "OVS"):
590 net_vlan
= self
.db
.get_free_net_vlan()
592 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error
)
593 if net_provider
== 'OVS':
594 net_provider
= 'OVS' + ":" + str(net_vlan
)
596 network
['provider'] = net_provider
597 network
['type'] = net_type
598 network
['vlan'] = net_vlan
599 dhcp_integrity
= True
600 if 'enable_dhcp' in network
and network
['enable_dhcp']:
601 dhcp_integrity
= self
._check
_dhcp
_data
_integrity
(network
)
603 result
, content
= self
.db
.new_row('nets', network
, True, True)
605 if result
>= 0 and dhcp_integrity
:
607 bridge_net
[3] = content
608 if self
.config
.get("dhcp_server") and self
.config
['network_type'] == 'bridge':
609 if network
["name"] in self
.config
["dhcp_server"].get("nets", ()):
610 self
.config
["dhcp_nets"].append(content
)
611 self
.logger
.debug("dhcp_server: add new net", content
)
612 elif not bridge_net
and bridge_net
[0] in self
.config
["dhcp_server"].get("bridge_ifaces", ()):
613 self
.config
["dhcp_nets"].append(content
)
614 self
.logger
.debug("dhcp_server: add new net", content
, content
)
617 raise ovimException("Error posting network", HTTP_Internal_Server_Error
)
618 # TODO kei change update->edit
620 def edit_network(self
, network_id
, network
):
622 Update entwork data byt id
625 # Look for the previous data
626 where_
= {'uuid': network_id
}
627 result
, network_old
= self
.db
.get_table(FROM
='nets', WHERE
=where_
)
629 raise ovimException("Error updating network %s" % network_old
, HTTP_Internal_Server_Error
)
631 raise ovimException('network %s not found' % network_id
, HTTP_Not_Found
)
633 nbports
, content
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
634 WHERE
={'net_id': network_id
}, LIMIT
=100)
636 raise ovimException("http_put_network_id error %d %s" % (result
, network_old
), HTTP_Internal_Server_Error
)
638 if 'type' in network
and network
['type'] != network_old
[0]['type']:
639 raise ovimException("Can not change type of network while having ports attached",
640 HTTP_Method_Not_Allowed
)
641 if 'vlan' in network
and network
['vlan'] != network_old
[0]['vlan']:
642 raise ovimException("Can not change vlan of network while having ports attached",
643 HTTP_Method_Not_Allowed
)
646 net_provider
= network
.get('provider', network_old
[0]['provider'])
647 net_type
= network
.get('type', network_old
[0]['type'])
648 net_bind_net
= network
.get("bind_net")
649 net_bind_type
= network
.get("bind_type")
651 # look for a valid net
652 if self
._check
_valid
_uuid
(net_bind_net
):
653 net_bind_key
= "uuid"
655 net_bind_key
= "name"
656 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
658 raise ovimException('Getting nets from db ' + content
, HTTP_Internal_Server_Error
)
660 raise ovimException("bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
662 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
),
664 network
["bind_net"] = content
[0]["uuid"]
666 if net_bind_type
[0:5] != "vlan:":
667 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
668 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
669 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
672 if net_provider
[:9] == "openflow:":
673 if net_type
!= "ptp" and net_type
!= "data":
674 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request
)
676 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
677 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
678 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
680 # insert in data base
681 result
, content
= self
.db
.update_rows('nets', network
, WHERE
={'uuid': network_id
}, log
=True)
683 # if result > 0 and nbports>0 and 'admin_state_up' in network
684 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
689 self
.net_update_ofc_thread(network_id
)
690 except ovimException
as e
:
691 raise ovimException("Error while launching openflow rules in network '{}' {}"
692 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
693 except Exception as e
:
694 raise ovimException("Error while launching openflow rules in network '{}' {}"
695 .format(network_id
, str(e
)), HTTP_Internal_Server_Error
)
697 if self
.config
.get("dhcp_server"):
698 if network_id
in self
.config
["dhcp_nets"]:
699 self
.config
["dhcp_nets"].remove(network_id
)
700 if network
.get("name", network_old
[0]["name"]) in self
.config
["dhcp_server"].get("nets", ()):
701 self
.config
["dhcp_nets"].append(network_id
)
703 net_bind
= network
.get("bind_type", network_old
[0]["bind_type"])
704 if net_bind
and net_bind
and net_bind
[:7] == "bridge:" and net_bind
[7:] in self
.config
["dhcp_server"].get(
705 "bridge_ifaces", ()):
706 self
.config
["dhcp_nets"].append(network_id
)
709 raise ovimException(content
, -result
)
711 def delete_network(self
, network_id
):
713 Delete network by network id
714 :param network_id: network id
718 # delete from the data base
719 result
, content
= self
.db
.delete_row('nets', network_id
)
722 raise ovimException("Network %s not found " % network_id
, HTTP_Not_Found
)
724 for brnet
in self
.config
['bridge_nets']:
725 if brnet
[3] == network_id
:
728 if self
.config
.get("dhcp_server") and network_id
in self
.config
["dhcp_nets"]:
729 self
.config
["dhcp_nets"].remove(network_id
)
732 raise ovimException("Error deleting network %s" % network_id
, HTTP_Internal_Server_Error
)
734 def get_openflow_rules(self
, network_id
=None):
736 Get openflow id from DB
737 :param network_id: Network id, if none all networks will be retrieved
738 :return: Return a list with Openflow rules per net
744 where_
= {"net_id": network_id
}
745 result
, content
= self
.db
.get_table(
746 SELECT
=("name", "net_id", "ofc_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
747 WHERE
=where_
, FROM
='of_flows')
750 raise ovimException(str(content
), -result
)
753 def edit_openflow_rules(self
, network_id
=None):
756 To make actions over the net. The action is to reinstall the openflow rules
757 network_id can be 'all'
758 :param network_id: Network id, if none all networks will be retrieved
759 :return : Number of nets updated
766 where_
= {"uuid": network_id
}
767 result
, content
= self
.db
.get_table(SELECT
=("uuid", "type"), WHERE
=where_
, FROM
='nets')
770 raise ovimException(str(content
), -result
)
773 if net
["type"] != "ptp" and net
["type"] != "data":
778 self
.net_update_ofc_thread(net
['uuid'])
779 except ovimException
as e
:
780 raise ovimException("Error updating network'{}' {}".format(net
['uuid'], str(e
)),
781 HTTP_Internal_Server_Error
)
782 except Exception as e
:
783 raise ovimException("Error updating network '{}' {}".format(net
['uuid'], str(e
)),
784 HTTP_Internal_Server_Error
)
788 def delete_openflow_rules(self
, ofc_id
=None):
790 To make actions over the net. The action is to delete ALL openflow rules
791 :return: return operation result
795 if 'Default' in self
.config
['ofcs_thread']:
796 r
, c
= self
.config
['ofcs_thread']['Default'].insert_task("clear-all")
798 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
800 elif ofc_id
in self
.config
['ofcs_thread']:
801 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("clear-all")
805 raise ovimException(str(c
), -r
)
807 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
810 def get_openflow_ports(self
, ofc_id
=None):
812 Obtain switch ports names of openflow controller
813 :return: Return flow ports in DB
816 if 'Default' in self
.config
['ofcs_thread']:
817 conn
= self
.config
['ofcs_thread']['Default'].OF_connector
819 raise ovimException("Default Openflow controller not not running", HTTP_Not_Found
)
821 if ofc_id
in self
.config
['ofcs_thread']:
822 conn
= self
.config
['ofcs_thread'][ofc_id
].OF_connector
824 raise ovimException("Openflow controller not found with ofc_id={}".format(ofc_id
), HTTP_Not_Found
)
827 def get_ports(self
, columns
=None, filter={}, limit
=None):
828 # result, content = my.db.get_ports(where_)
829 result
, content
= self
.db
.get_table(SELECT
=columns
, WHERE
=filter, FROM
='ports', LIMIT
=limit
)
831 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
832 raise ovimException(str(content
), -result
)
834 convert_boolean(content
, ('admin_state_up',))
837 def new_port(self
, port_data
):
838 port_data
['type'] = 'external'
839 if port_data
.get('net_id'):
840 # check that new net has the correct type
841 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
843 raise ovimException(str(new_net
), -result
)
844 # insert in data base
845 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
847 if 'net_id' in port_data
:
849 self
.net_update_ofc_thread(port_data
['net_id'])
850 except ovimException
as e
:
851 raise ovimException("Cannot insert a task for updating network '{}' {}"
852 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
853 except Exception as e
:
854 raise ovimException("Cannot insert a task for updating network '{}' {}"
855 .format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
859 raise ovimException(str(uuid
), -result
)
861 def new_external_port(self
, port_data
):
863 Create new external port and check port mapping correspondence
864 :param port_data: port_data = {
865 'region': 'datacenter region',
866 'compute_node': 'compute node id',
867 'pci': 'pci port address',
870 'tenant_id': 'tenant id',
873 'ip_address': 'ip address - optional'}
877 port_data
['type'] = 'external'
879 if port_data
.get('net_id'):
880 # check that new net has the correct type
881 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
883 raise ovimException(str(new_net
), -result
)
884 # insert in data base
887 if port_data
.get('region'):
888 db_filter
['region'] = port_data
['region']
889 if port_data
.get('pci'):
890 db_filter
['pci'] = port_data
['pci']
891 if port_data
.get('compute_node'):
892 db_filter
['compute_node'] = port_data
['compute_node']
894 columns
= ['ofc_id', 'switch_dpid', 'switch_port', 'switch_mac', 'pci']
895 port_mapping_data
= self
.get_of_port_mappings(columns
, db_filter
)
897 if not len(port_mapping_data
):
898 raise ovimException("No port mapping founded for '{}'".format(str(db_filter
)),
900 elif len(port_mapping_data
) > 1:
901 raise ovimException("Wrong port data was given, please check pci, region & compute id data",
904 port_data
['ofc_id'] = port_mapping_data
[0]['ofc_id']
905 port_data
['switch_dpid'] = port_mapping_data
[0]['switch_dpid']
906 port_data
['switch_port'] = port_mapping_data
[0]['switch_port']
907 port_data
['switch_mac'] = port_mapping_data
[0]['switch_mac']
909 # remove from compute_node, region and pci of_port_data to adapt to 'ports' structure
910 if 'region' in port_data
:
911 del port_data
['region']
912 if 'pci' in port_data
:
914 if 'compute_node' in port_data
:
915 del port_data
['compute_node']
917 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
920 self
.net_update_ofc_thread(port_data
['net_id'], port_data
['ofc_id'])
921 except ovimException
as e
:
922 raise ovimException("Cannot insert a task for updating network '{}' {}".
923 format(port_data
['net_id'], str(e
)), HTTP_Internal_Server_Error
)
924 except Exception as e
:
925 raise ovimException("Cannot insert a task for updating network '{}' {}"
926 .format(port_data
['net_id'], e
), HTTP_Internal_Server_Error
)
929 raise ovimException(str(uuid
), -result
)
931 def net_update_ofc_thread(self
, net_id
, ofc_id
=None, switch_dpid
=None):
933 Insert a update net task by net id or ofc_id for each ofc thread
934 :param net_id: network id
935 :param ofc_id: openflow controller id
936 :param switch_dpid: switch dpid
940 raise ovimException("No net_id received", HTTP_Internal_Server_Error
)
943 c
= 'No valid ofc_id or switch_dpid received'
946 ports
= self
.get_ports(filter={"net_id": net_id
})
948 port_ofc_id
= port
.get('ofc_id', None)
950 ofc_id
= port
['ofc_id']
951 switch_dpid
= port
['switch_dpid']
953 #TODO if not ofc_id: look at database table ofcs
956 # If no ofc_id found it, default ofc_id is used.
957 if not ofc_id
and not switch_dpid
:
960 if ofc_id
and ofc_id
in self
.config
['ofcs_thread']:
961 r
, c
= self
.config
['ofcs_thread'][ofc_id
].insert_task("update-net", net_id
)
964 ofcs_dpid_list
= self
.config
['ofcs_thread_dpid']
965 for ofc_t
in ofcs_dpid_list
:
966 if switch_dpid
in ofc_t
:
967 r
, c
= ofc_t
[switch_dpid
].insert_task("update-net", net_id
)
970 message
= "Cannot insert a task for updating network '{}', {}".format(net_id
, c
)
971 self
.logger
.error(message
)
972 raise ovimException(message
, HTTP_Internal_Server_Error
)
974 def delete_port(self
, port_id
):
975 # Look for the previous port data
976 result
, ports
= self
.db
.get_table(WHERE
={'uuid': port_id
, "type": "external"}, FROM
='ports')
978 raise ovimException("Cannot get port info from database: {}".format(ports
), http_code
=-result
)
979 # delete from the data base
980 result
, content
= self
.db
.delete_row('ports', port_id
)
982 raise ovimException("External port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
984 raise ovimException("Cannot delete port from database: {}".format(content
), http_code
=-result
)
986 network
= ports
[0].get('net_id', None)
991 self
.net_update_ofc_thread(network
, ofc_id
=ports
[0]["ofc_id"], switch_dpid
=ports
[0]["switch_dpid"])
992 except ovimException
as e
:
993 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network
, str(e
)),
994 HTTP_Internal_Server_Error
)
995 except Exception as e
:
996 raise ovimException("Cannot insert a task for delete network '{}' {}".format(network
, str(e
)),
997 HTTP_Internal_Server_Error
)
1001 def edit_port(self
, port_id
, port_data
, admin
=True):
1002 # Look for the previous port data
1003 result
, content
= self
.db
.get_table(FROM
="ports", WHERE
={'uuid': port_id
})
1005 raise ovimException("Cannot get port info from database: {}".format(content
), http_code
=-result
)
1007 raise ovimException("Port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
1012 if 'net_id' in port_data
:
1014 old_net
= port
.get('net_id', None)
1015 new_net
= port_data
['net_id']
1016 if old_net
!= new_net
:
1019 nets
.append(new_net
) # put first the new net, so that new openflow rules are created before removing the old ones
1021 nets
.append(old_net
)
1022 if port
['type'] == 'instance:bridge' or port
['type'] == 'instance:ovs':
1023 raise ovimException("bridge interfaces cannot be attached to a different net", http_code
=HTTP_Forbidden
)
1024 elif port
['type'] == 'external' and not admin
:
1025 raise ovimException("Needed admin privileges",http_code
=HTTP_Unauthorized
)
1027 # check that new net has the correct type
1028 result
, new_net_dict
= self
.db
.check_target_net(new_net
, None, port
['type'])
1030 raise ovimException("Error {}".format(new_net_dict
), http_code
=HTTP_Conflict
)
1031 # change VLAN for SR-IOV ports
1032 if result
>= 0 and port
["type"] == "instance:data" and port
["model"] == "VF": # TODO consider also VFnotShared
1034 port_data
["vlan"] = None
1036 port_data
["vlan"] = new_net_dict
["vlan"]
1037 # get host where this VM is allocated
1038 result
, content
= self
.db
.get_table(FROM
="instances", WHERE
={"uuid": port
["instance_id"]})
1040 host_id
= content
[0]["host_id"]
1042 # insert in data base
1044 result
, content
= self
.db
.update_rows('ports', port_data
, WHERE
={'uuid': port_id
}, log
=False)
1045 port
.update(port_data
)
1047 # Insert task to complete actions
1051 self
.net_update_ofc_thread(net_id
, port
["ofc_id"], switch_dpid
=port
["switch_dpid"])
1052 except ovimException
as e
:
1053 raise ovimException("Error updating network'{}' {}".format(net_id
, str(e
)),
1054 HTTP_Internal_Server_Error
)
1055 except Exception as e
:
1056 raise ovimException("Error updating network '{}' {}".format(net_id
, str(e
)),
1057 HTTP_Internal_Server_Error
)
1060 r
, v
= self
.config
['host_threads'][host_id
].insert_task("edit-iface", port_id
, old_net
, new_net
)
1062 self
.logger
.error("Error updating network '{}' {}".format(r
,v
))
1063 # TODO Do something if fails
1067 raise ovimException("Error {}".format(content
), http_code
=-result
)
1069 def new_of_controller(self
, ofc_data
):
1071 Create a new openflow controller into DB
1072 :param ofc_data: Dict openflow controller data
1073 :return: openflow controller dpid
1076 result
, ofc_uuid
= self
.db
.new_row('ofcs', ofc_data
, True, True)
1078 raise ovimException("New ofc Error %s" % ofc_uuid
, HTTP_Internal_Server_Error
)
1080 ofc_data
['uuid'] = ofc_uuid
1081 of_conn
= self
._load
_of
_module
(ofc_data
)
1082 self
._create
_ofc
_task
(ofc_uuid
, ofc_data
['dpid'], of_conn
)
1086 def edit_of_controller(self
, of_id
, ofc_data
):
1088 Edit an openflow controller entry from DB
1092 raise ovimException("No data received during uptade OF contorller", http_code
=HTTP_Internal_Server_Error
)
1094 old_of_controller
= self
.show_of_controller(of_id
)
1096 if old_of_controller
:
1097 result
, content
= self
.db
.update_rows('ofcs', ofc_data
, WHERE
={'uuid': of_id
}, log
=False)
1101 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1104 raise ovimException("Error uptating OF contorller with uuid {}".format(of_id
),
1105 http_code
=HTTP_Internal_Server_Error
)
1107 def delete_of_controller(self
, of_id
):
1109 Delete an openflow controller from DB.
1110 :param of_id: openflow controller dpid
1114 ofc
= self
.show_of_controller(of_id
)
1116 result
, content
= self
.db
.delete_row("ofcs", of_id
)
1118 raise ovimException("Cannot delete ofc from database: {}".format(content
), http_code
=-result
)
1120 raise ovimException("ofc {} not found ".format(content
), http_code
=HTTP_Not_Found
)
1122 ofc_thread
= self
.config
['ofcs_thread'][of_id
]
1123 del self
.config
['ofcs_thread'][of_id
]
1124 for ofc_th
in self
.config
['ofcs_thread_dpid']:
1125 if ofc
['dpid'] in ofc_th
:
1126 self
.config
['ofcs_thread_dpid'].remove(ofc_th
)
1128 ofc_thread
.insert_task("exit")
1133 def show_of_controller(self
, uuid
):
1135 Show an openflow controller by dpid from DB.
1136 :param db_filter: List with where query parameters
1140 result
, content
= self
.db
.get_table(FROM
='ofcs', WHERE
={"uuid": uuid
}, LIMIT
=100)
1143 raise ovimException("Openflow controller with uuid '{}' not found".format(uuid
),
1144 http_code
=HTTP_Not_Found
)
1146 raise ovimException("Openflow controller with uuid '{}' error".format(uuid
),
1147 http_code
=HTTP_Internal_Server_Error
)
1150 def get_of_controllers(self
, columns
=None, db_filter
={}, limit
=None):
1152 Show an openflow controllers from DB.
1153 :param columns: List with SELECT query parameters
1154 :param db_filter: List with where query parameters
1155 :param limit: result Limit
1158 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='ofcs', WHERE
=db_filter
, LIMIT
=limit
)
1161 raise ovimException(str(content
), -result
)
1165 def get_tenants(self
, columns
=None, db_filter
={}, limit
=None):
1167 Retrieve tenant list from DB
1168 :param columns: List with SELECT query parameters
1169 :param db_filter: List with where query parameters
1170 :param limit: result limit
1173 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=columns
, WHERE
=db_filter
, LIMIT
=limit
)
1175 raise ovimException('get_tenatns Error {}'.format(str(content
)), -result
)
1177 convert_boolean(content
, ('enabled',))
1180 def show_tenant_id(self
, tenant_id
):
1182 Get tenant from DB by id
1183 :param tenant_id: tenant id
1186 result
, content
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid', 'name', 'description', 'enabled'),
1187 WHERE
={"uuid": tenant_id
})
1189 raise ovimException(str(content
), -result
)
1191 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1193 convert_boolean(content
, ('enabled',))
1196 def new_tentant(self
, tenant
):
1198 Create a tenant and store in DB
1199 :param tenant: Dictionary with tenant data
1200 :return: the uuid of created tenant. Raise exception upon error
1203 # insert in data base
1204 result
, tenant_uuid
= self
.db
.new_tenant(tenant
)
1209 raise ovimException(str(tenant_uuid
), -result
)
1211 def delete_tentant(self
, tenant_id
):
1213 Delete a tenant from the database.
1214 :param tenant_id: Tenant id
1215 :return: delete tenant id
1219 r
, tenants_flavors
= self
.db
.get_table(FROM
='tenants_flavors', SELECT
=('flavor_id', 'tenant_id'),
1220 WHERE
={'tenant_id': tenant_id
})
1222 tenants_flavors
= ()
1223 r
, tenants_images
= self
.db
.get_table(FROM
='tenants_images', SELECT
=('image_id', 'tenant_id'),
1224 WHERE
={'tenant_id': tenant_id
})
1228 result
, content
= self
.db
.delete_row('tenants', tenant_id
)
1230 raise ovimException("tenant '%s' not found" % tenant_id
, HTTP_Not_Found
)
1232 for flavor
in tenants_flavors
:
1233 self
.db
.delete_row_by_key("flavors", "uuid", flavor
['flavor_id'])
1234 for image
in tenants_images
:
1235 self
.db
.delete_row_by_key("images", "uuid", image
['image_id'])
1238 raise ovimException("Error deleting tenant '%s' " % tenant_id
, HTTP_Internal_Server_Error
)
1240 def edit_tenant(self
, tenant_id
, tenant_data
):
1242 Update a tenant data identified by tenant id
1243 :param tenant_id: tenant id
1244 :param tenant_data: Dictionary with tenant data
1248 # Look for the previous data
1249 result
, tenant_data_old
= self
.db
.get_table(FROM
='tenants', WHERE
={'uuid': tenant_id
})
1251 raise ovimException("Error updating tenant with uuid='{}': {}".format(tenant_id
, tenant_data_old
),
1252 HTTP_Internal_Server_Error
)
1254 raise ovimException("tenant with uuid='{}' not found".format(tenant_id
), HTTP_Not_Found
)
1256 # insert in data base
1257 result
, content
= self
.db
.update_rows('tenants', tenant_data
, WHERE
={'uuid': tenant_id
}, log
=True)
1261 raise ovimException(str(content
), -result
)
1263 def set_of_port_mapping(self
, of_maps
, ofc_id
=None, switch_dpid
=None, region
=None):
1265 Create new port mapping entry
1266 :param of_maps: List with port mapping information
1267 # maps =[{"ofc_id": <ofc_id>,"region": datacenter region,"compute_node": compute uuid,"pci": pci adress,
1268 "switch_dpid": swith dpid,"switch_port": port name,"switch_mac": mac}]
1269 :param ofc_id: ofc id
1270 :param switch_dpid: switch dpid
1271 :param region: datacenter region id
1277 map['ofc_id'] = ofc_id
1279 map['switch_dpid'] = switch_dpid
1281 map['region'] = region
1283 for of_map
in of_maps
:
1284 result
, uuid
= self
.db
.new_row('of_port_mappings', of_map
, True)
1286 of_map
["uuid"] = uuid
1288 raise ovimException(str(uuid
), -result
)
1291 def clear_of_port_mapping(self
, db_filter
={}):
1293 Clear port mapping filtering using db_filter dict
1294 :param db_filter: Parameter to filter during remove process
1297 result
, content
= self
.db
.delete_row_by_dict(FROM
='of_port_mappings', WHERE
=db_filter
)
1302 raise ovimException("Error deleting of_port_mappings with filter='{}'".format(str(db_filter
)),
1303 HTTP_Internal_Server_Error
)
1305 def get_of_port_mappings(self
, column
=None, db_filter
=None, db_limit
=None):
1307 Retrive port mapping from DB
1312 result
, content
= self
.db
.get_table(SELECT
=column
, WHERE
=db_filter
, FROM
='of_port_mappings', LIMIT
=db_limit
)
1315 self
.logger
.error("get_of_port_mappings Error %d %s", result
, content
)
1316 raise ovimException(str(content
), -result
)
1320 def get_dhcp_controller(self
):
1322 Create an host_thread object for manage openvim controller and not create a thread for itself
1323 :return: dhcp_host openvim controller object
1326 if 'openvim_controller' in self
.config
['host_threads']:
1327 return self
.config
['host_threads']['openvim_controller']
1330 controller_ip
= self
.config
['ovs_controller_ip']
1331 ovs_controller_user
= self
.config
['ovs_controller_user']
1333 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
1334 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
1336 dhcp_host
= ht
.host_thread(name
='openvim_controller', user
=ovs_controller_user
, host
=controller_ip
,
1338 db_lock
=self
.db_lock
, test
=host_test_mode
,
1339 image_path
=self
.config
['image_path'], version
=self
.config
['version'],
1340 host_id
='openvim_controller', develop_mode
=host_develop_mode
,
1341 develop_bridge_iface
=bridge_ifaces
)
1343 self
.config
['host_threads']['openvim_controller'] = dhcp_host
1344 if not host_test_mode
:
1345 dhcp_host
.ssh_connect()
1348 def launch_dhcp_server(self
, vlan
, first_ip
, last_ip
, cidr
, gateway
):
1350 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
1351 :param vlan: vlan identifier
1352 :param first_ip: First dhcp range ip
1353 :param last_ip: Last dhcp range ip
1354 :param cidr: net cidr
1355 :param gateway: net gateway
1358 ip_tools
= IPNetwork(cidr
)
1359 dhcp_netmask
= str(ip_tools
.netmask
)
1360 ip_range
= [first_ip
, last_ip
]
1362 dhcp_path
= self
.config
['ovs_controller_file_path']
1364 controller_host
= self
.get_dhcp_controller()
1365 controller_host
.create_linux_bridge(vlan
)
1366 controller_host
.create_dhcp_interfaces(vlan
, first_ip
, dhcp_netmask
)
1367 controller_host
.launch_dhcp_server(vlan
, ip_range
, dhcp_netmask
, dhcp_path
, gateway
)
1369 if __name__
== "__main__":
1371 parser
= argparse
.ArgumentParser()
1372 parser
.add_argument("-v","--version", help="increase output verbosity", action
="store_true")
1373 args
= parser
.parse_args()
1375 print ('openvimd version {} {}'.format(ovim
.get_version(), ovim
.get_version_date()))
1376 print ('(c) Copyright Telefonica')