1 # -*- coding: utf-8 -*-
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openvim
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
12 # http://www.apache.org/licenses/LICENSE-2.0
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
25 This is the thread for the http server North API.
26 Two thread will be launched, with normal and administrative permissions.
29 __author__
= "Alfonso Tierno, Leonardo Mirabal"
30 __date__
= "$06-Feb-2017 12:07:15$"
37 import host_thread
as ht
38 import dhcp_thread
as dt
39 import openflow_thread
as oft
40 from netaddr
import IPNetwork
41 from jsonschema
import validate
as js_v
, exceptions
as js_e
43 HTTP_Bad_Request
= 400
44 HTTP_Unauthorized
= 401
47 HTTP_Method_Not_Allowed
= 405
48 HTTP_Not_Acceptable
= 406
49 HTTP_Request_Timeout
= 408
51 HTTP_Service_Unavailable
= 503
52 HTTP_Internal_Server_Error
= 500
55 def convert_boolean(data
, items
):
56 '''Check recursively the content of data, and if there is an key contained in items, convert value from string to boolean
57 It assumes that bandwidth is well formed
59 'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
60 'items': tuple of keys to convert
64 if type(data
) is dict:
66 if type(data
[k
]) is dict or type(data
[k
]) is tuple or type(data
[k
]) is list:
67 convert_boolean(data
[k
], items
)
69 if type(data
[k
]) is str:
70 if data
[k
] == "false":
72 elif data
[k
] == "true":
74 if type(data
) is tuple or type(data
) is list:
76 if type(k
) is dict or type(k
) is tuple or type(k
) is list:
77 convert_boolean(k
, items
)
81 class ovimException(Exception):
82 def __init__(self
, message
, http_code
=HTTP_Bad_Request
):
83 self
.http_code
= http_code
84 Exception.__init
__(self
, message
)
88 running_info
= {} #TODO OVIM move the info of running threads from config_dic to this static variable
89 def __init__(self
, configuration
):
90 self
.config
= configuration
91 self
.logger
= logging
.getLogger(configuration
["logger_name"])
93 self
.db
= self
._create
_database
_connection
()
95 def _create_database_connection(self
):
96 db
= vim_db
.vim_db((self
.config
["network_vlan_range_start"], self
.config
["network_vlan_range_end"]),
97 self
.config
['log_level_db']);
98 if db
.connect(self
.config
['db_host'], self
.config
['db_user'], self
.config
['db_passwd'],
99 self
.config
['db_name']) == -1:
100 # self.logger.error("Cannot connect to database %s at %s@%s", self.config['db_name'], self.config['db_user'],
101 # self.config['db_host'])
102 raise ovimException("Cannot connect to database {} at {}@{}".format(self
.config
['db_name'],
103 self
.config
['db_user'],
104 self
.config
['db_host']) )
108 def _check_dhcp_data_integrity(network
):
110 Check if all dhcp parameter for anet are valid, if not will be calculated from cidr value
111 :param network: list with user nets paramters
114 if "cidr" in network
:
115 cidr
= network
["cidr"]
116 ip_tools
= IPNetwork(cidr
)
117 cidr_len
= ip_tools
.prefixlen
121 ips
= IPNetwork(cidr
)
122 if "dhcp_first_ip" not in network
:
123 network
["dhcp_first_ip"] = str(ips
[2])
124 if "dhcp_last_ip" not in network
:
125 network
["dhcp_last_ip"] = str(ips
[-2])
126 if "gateway_ip" not in network
:
127 network
["gateway_ip"] = str(ips
[1])
134 def _check_valid_uuid(uuid
):
135 id_schema
= {"type": "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
137 js_v(uuid
, id_schema
)
139 except js_e
.ValidationError
:
142 def start_service(self
):
143 #if self.running_info:
144 # return #TODO service can be checked and rebuild broken threads
145 r
= self
.db
.get_db_version()
147 raise ovimException("DATABASE is not a VIM one or it is a '0.0' version. Try to upgrade to version '{}' with "\
148 "'./database_utils/migrate_vim_db.sh'".format(self
.config
["database_version"]) )
149 elif r
[1]!=self
.config
["database_version"]:
150 raise ovimException("DATABASE wrong version '{}'. Try to upgrade/downgrade to version '{}' with "\
151 "'./database_utils/migrate_vim_db.sh'".format(r
[1], self
.config
["database_version"]) )
153 # create database connection for openflow threads
154 db_of
= self
._create
_database
_connection
()
155 self
.config
["db"] = db_of
156 db_lock
= threading
.Lock()
157 self
.config
["db_lock"] = db_lock
159 # precreate interfaces; [bridge:<host_bridge_name>, VLAN used at Host, uuid of network camping in this bridge, speed in Gbit/s
160 self
.config
['dhcp_nets'] = []
161 self
.config
['bridge_nets'] = []
162 for bridge
, vlan_speed
in self
.config
["bridge_ifaces"].items():
163 # skip 'development_bridge'
164 if self
.config
['mode'] == 'development' and self
.config
['development_bridge'] == bridge
:
166 self
.config
['bridge_nets'].append([bridge
, vlan_speed
[0], vlan_speed
[1], None])
168 # check if this bridge is already used (present at database) for a network)
169 used_bridge_nets
= []
170 for brnet
in self
.config
['bridge_nets']:
171 r
, nets
= db_of
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'provider': "bridge:" + brnet
[0]})
173 brnet
[3] = nets
[0]['uuid']
174 used_bridge_nets
.append(brnet
[0])
175 if self
.config
.get("dhcp_server"):
176 if brnet
[0] in self
.config
["dhcp_server"]["bridge_ifaces"]:
177 self
.config
['dhcp_nets'].append(nets
[0]['uuid'])
178 if len(used_bridge_nets
) > 0:
179 self
.logger
.info("found used bridge nets: " + ",".join(used_bridge_nets
))
180 # get nets used by dhcp
181 if self
.config
.get("dhcp_server"):
182 for net
in self
.config
["dhcp_server"].get("nets", ()):
183 r
, nets
= db_of
.get_table(SELECT
=('uuid',), FROM
='nets', WHERE
={'name': net
})
185 self
.config
['dhcp_nets'].append(nets
[0]['uuid'])
187 # get host list from data base before starting threads
188 r
, hosts
= db_of
.get_table(SELECT
=('name', 'ip_name', 'user', 'uuid'), FROM
='hosts', WHERE
={'status': 'ok'})
190 raise ovimException("Cannot get hosts from database {}".format(hosts
))
191 # create connector to the openflow controller
192 of_test_mode
= False if self
.config
['mode'] == 'normal' or self
.config
['mode'] == "OF only" else True
195 OF_conn
= oft
.of_test_connector({"of_debug": self
.config
['log_level_of']})
197 # load other parameters starting by of_ from config dict in a temporal dict
198 temp_dict
= {"of_ip": self
.config
['of_controller_ip'],
199 "of_port": self
.config
['of_controller_port'],
200 "of_dpid": self
.config
['of_controller_dpid'],
201 "of_debug": self
.config
['log_level_of']
203 for k
, v
in self
.config
.iteritems():
204 if type(k
) is str and k
[0:3] == "of_" and k
[0:13] != "of_controller":
206 if self
.config
['of_controller'] == 'opendaylight':
208 elif "of_controller_module" in self
.config
:
209 module
= self
.config
["of_controller_module"]
211 module
= self
.config
['of_controller']
214 module_info
= imp
.find_module(module
)
216 OF_conn
= imp
.load_module("OF_conn", *module_info
)
218 OF_conn
= OF_conn
.OF_conn(temp_dict
)
219 except Exception as e
:
220 self
.logger
.error("Cannot open the Openflow controller '%s': %s", type(e
).__name
__, str(e
))
221 if module_info
and module_info
[0]:
222 file.close(module_info
[0])
224 except (IOError, ImportError) as e
:
225 if module_info
and module_info
[0]:
226 file.close(module_info
[0])
228 "Cannot open openflow controller module '%s'; %s: %s; revise 'of_controller' field of configuration file.",
229 module
, type(e
).__name
__, str(e
))
230 raise ovimException("Cannot open openflow controller module '{}'; {}: {}; revise 'of_controller' field of configuration file.".fromat(
231 module
, type(e
).__name
__, str(e
)))
234 # create openflow thread
235 thread
= oft
.openflow_thread(OF_conn
, of_test
=of_test_mode
, db
=db_of
, db_lock
=db_lock
,
236 pmp_with_same_vlan
=self
.config
['of_controller_nets_with_same_vlan'],
237 debug
=self
.config
['log_level_of'])
238 r
, c
= thread
.OF_connector
.obtain_port_correspondence()
240 raise ovimException("Cannot get openflow information %s", c
)
242 self
.config
['of_thread'] = thread
244 # create dhcp_server thread
245 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
246 dhcp_params
= self
.config
.get("dhcp_server")
248 thread
= dt
.dhcp_thread(dhcp_params
=dhcp_params
, test
=host_test_mode
, dhcp_nets
=self
.config
["dhcp_nets"],
249 db
=db_of
, db_lock
=db_lock
, debug
=self
.config
['log_level_of'])
251 self
.config
['dhcp_thread'] = thread
253 # Create one thread for each host
254 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
255 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
256 host_develop_bridge_iface
= self
.config
.get('development_bridge', None)
257 self
.config
['host_threads'] = {}
259 host
['image_path'] = '/opt/VNF/images/openvim'
260 thread
= ht
.host_thread(name
=host
['name'], user
=host
['user'], host
=host
['ip_name'], db
=db_of
, db_lock
=db_lock
,
261 test
=host_test_mode
, image_path
=self
.config
['image_path'], version
=self
.config
['version'],
262 host_id
=host
['uuid'], develop_mode
=host_develop_mode
,
263 develop_bridge_iface
=host_develop_bridge_iface
)
265 self
.config
['host_threads'][host
['uuid']] = thread
267 # create ovs dhcp thread
268 result
, content
= self
.db
.get_table(FROM
='nets')
270 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
271 raise ovimException(str(content
), -result
)
274 net_type
= net
['type']
275 if (net_type
== 'bridge_data' or net_type
== 'bridge_man') \
276 and net
["provider"][:4] == 'OVS:' and net
["enable_dhcp"] == "true":
277 self
.launch_dhcp_server(net
['vlan'],
278 net
['dhcp_first_ip'],
283 def stop_service(self
):
284 threads
= self
.config
.get('host_threads', {})
285 if 'of_thread' in self
.config
:
286 threads
['of'] = (self
.config
['of_thread'])
287 if 'dhcp_thread' in self
.config
:
288 threads
['dhcp'] = (self
.config
['dhcp_thread'])
290 for thread
in threads
.values():
291 thread
.insert_task("exit")
292 for thread
in threads
.values():
295 def get_networks(self
, columns
=None, filter={}, limit
=None):
297 Retreive networks available
298 :param columns: List with select query parameters
299 :param filter: List with where query parameters
300 :param limit: Query limit result
303 result
, content
= self
.db
.get_table(SELECT
=columns
, FROM
='nets', WHERE
=filter, LIMIT
=limit
)
306 raise ovimException(str(content
), -result
)
308 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
312 def show_network(self
, network_id
, filter={}):
314 Get network from DB by id
315 :param network_id: net Id
322 raise ovimException("Not network id was not found")
323 filter['uuid'] = network_id
325 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
=filter, LIMIT
=100)
328 raise ovimException(str(content
), -result
)
330 raise ovimException("show_network network '%s' not found" % network_id
, -result
)
332 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
334 result
, ports
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
335 WHERE
={'net_id': network_id
}, LIMIT
=100)
337 content
[0]['ports'] = ports
339 convert_boolean(content
, ('shared', 'admin_state_up', 'enable_dhcp'))
342 def new_network(self
, network
):
347 tenant_id
= network
.get('tenant_id')
350 result
, _
= self
.db
.get_table(FROM
='tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
, "enabled": True})
352 raise ovimException("set_network error, no tenant founded", -result
)
356 net_provider
= network
.get('provider')
357 net_type
= network
.get('type')
358 net_vlan
= network
.get("vlan")
359 net_bind_net
= network
.get("bind_net")
360 net_bind_type
= network
.get("bind_type")
361 name
= network
["name"]
363 # check if network name ends with :<vlan_tag> and network exist in order to make and automated bindning
364 vlan_index
= name
.rfind(":")
365 if not net_bind_net
and not net_bind_type
and vlan_index
> 1:
367 vlan_tag
= int(name
[vlan_index
+ 1:])
368 if not vlan_tag
and vlan_tag
< 4096:
369 net_bind_net
= name
[:vlan_index
]
370 net_bind_type
= "vlan:" + name
[vlan_index
+ 1:]
375 # look for a valid net
376 if self
._check
_valid
_uuid
(net_bind_net
):
377 net_bind_key
= "uuid"
379 net_bind_key
= "name"
380 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
382 raise ovimException(' getting nets from db ' + content
, HTTP_Internal_Server_Error
)
384 raise ovimException(" bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
386 raise ovimException(" more than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
387 network
["bind_net"] = content
[0]["uuid"]
390 if net_bind_type
[0:5] != "vlan:":
391 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
392 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
393 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
395 network
["bind_type"] = net_bind_type
398 if net_provider
[:9] == "openflow:":
400 if net_type
!= "ptp" and net_type
!= "data":
401 raise ovimException(" only 'ptp' or 'data' net types can be bound to 'openflow'",
407 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
408 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound "
409 "to 'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
411 net_type
= 'bridge_man'
414 net_type
= 'bridge_man'
417 if net_provider
[:7] == 'bridge:':
418 # check it is one of the pre-provisioned bridges
419 bridge_net_name
= net_provider
[7:]
420 for brnet
in self
.config
['bridge_nets']:
421 if brnet
[0] == bridge_net_name
: # free
423 raise ovimException("invalid 'provider:physical', "
424 "bridge '%s' is already used" % bridge_net_name
, HTTP_Conflict
)
428 # if bridge_net==None:
429 # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the
430 # provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
433 elif self
.config
['network_type'] == 'bridge' and (net_type
== 'bridge_data' or net_type
== 'bridge_man'):
434 # look for a free precreated nets
435 for brnet
in self
.config
['bridge_nets']:
436 if not brnet
[3]: # free
438 if net_type
== 'bridge_man': # look for the smaller speed
439 if brnet
[2] < bridge_net
[2]:
441 else: # look for the larger speed
442 if brnet
[2] > bridge_net
[2]:
448 raise ovimException("Max limits of bridge networks reached. Future versions of VIM "
449 "will overcome this limit", HTTP_Bad_Request
)
451 self
.logger
.debug("using net " + bridge_net
)
452 net_provider
= "bridge:" + bridge_net
[0]
453 net_vlan
= bridge_net
[1]
454 elif net_type
== 'bridge_data' or net_type
== 'bridge_man' and self
.config
['network_type'] == 'ovs':
456 if not net_vlan
and (net_type
== "data" or net_type
== "ptp" or net_provider
== "OVS"):
457 net_vlan
= self
.db
.get_free_net_vlan()
459 raise ovimException("Error getting an available vlan", HTTP_Internal_Server_Error
)
460 if net_provider
== 'OVS':
461 net_provider
= 'OVS' + ":" + str(net_vlan
)
463 network
['provider'] = net_provider
464 network
['type'] = net_type
465 network
['vlan'] = net_vlan
466 dhcp_integrity
= True
467 if 'enable_dhcp' in network
and network
['enable_dhcp']:
468 dhcp_integrity
= self
._check
_dhcp
_data
_integrity
(network
)
470 result
, content
= self
.db
.new_row('nets', network
, True, True)
472 if result
>= 0 and dhcp_integrity
:
474 bridge_net
[3] = content
475 if self
.config
.get("dhcp_server") and self
.config
['network_type'] == 'bridge':
476 if network
["name"] in self
.config
["dhcp_server"].get("nets", ()):
477 self
.config
["dhcp_nets"].append(content
)
478 self
.logger
.debug("dhcp_server: add new net", content
)
479 elif not bridge_net
and bridge_net
[0] in self
.config
["dhcp_server"].get("bridge_ifaces", ()):
480 self
.config
["dhcp_nets"].append(content
)
481 self
.logger
.debug("dhcp_server: add new net", content
, content
)
484 raise ovimException("Error posting network", HTTP_Internal_Server_Error
)
485 # TODO kei change update->edit
487 def edit_network(self
, network_id
, network
):
489 Update entwork data byt id
492 # Look for the previous data
493 where_
= {'uuid': network_id
}
494 result
, network_old
= self
.db
.get_table(FROM
='nets', WHERE
=where_
)
496 raise ovimException("Error updating network %s" % network_old
, HTTP_Internal_Server_Error
)
498 raise ovimException('network %s not found' % network_id
, HTTP_Not_Found
)
500 nbports
, content
= self
.db
.get_table(FROM
='ports', SELECT
=('uuid as port_id',),
501 WHERE
={'net_id': network_id
}, LIMIT
=100)
503 raise ovimException("http_put_network_id error %d %s" % (result
, network_old
), HTTP_Internal_Server_Error
)
505 if 'type' in network
and network
['type'] != network_old
[0]['type']:
506 raise ovimException("Can not change type of network while having ports attached",
507 HTTP_Method_Not_Allowed
)
508 if 'vlan' in network
and network
['vlan'] != network_old
[0]['vlan']:
509 raise ovimException("Can not change vlan of network while having ports attached",
510 HTTP_Method_Not_Allowed
)
513 net_provider
= network
.get('provider', network_old
[0]['provider'])
514 net_type
= network
.get('type', network_old
[0]['type'])
515 net_bind_net
= network
.get("bind_net")
516 net_bind_type
= network
.get("bind_type")
518 # look for a valid net
519 if self
._check
_valid
_uuid
(net_bind_net
):
520 net_bind_key
= "uuid"
522 net_bind_key
= "name"
523 result
, content
= self
.db
.get_table(FROM
='nets', WHERE
={net_bind_key
: net_bind_net
})
525 raise ovimException('Getting nets from db ' + content
, HTTP_Internal_Server_Error
)
527 raise ovimException("bind_net %s '%s'not found" % (net_bind_key
, net_bind_net
), HTTP_Bad_Request
)
529 raise ovimException("More than one bind_net %s '%s' found, use uuid" % (net_bind_key
, net_bind_net
),
531 network
["bind_net"] = content
[0]["uuid"]
533 if net_bind_type
[0:5] != "vlan:":
534 raise ovimException("Bad format for 'bind_type', must be 'vlan:<tag>'", HTTP_Bad_Request
)
535 if int(net_bind_type
[5:]) > 4095 or int(net_bind_type
[5:]) <= 0:
536 raise ovimException("bad format for 'bind_type', must be 'vlan:<tag>' with a tag between 1 and 4095",
539 if net_provider
[:9] == "openflow:":
540 if net_type
!= "ptp" and net_type
!= "data":
541 raise ovimException("Only 'ptp' or 'data' net types can be bound to 'openflow'", HTTP_Bad_Request
)
543 if net_type
!= "bridge_man" and net_type
!= "bridge_data":
544 raise ovimException("Only 'bridge_man' or 'bridge_data' net types can be bound to "
545 "'bridge', 'macvtap' or 'default", HTTP_Bad_Request
)
547 # insert in data base
548 result
, content
= self
.db
.update_rows('nets', network
, WHERE
={'uuid': network_id
}, log
=True)
550 # if result > 0 and nbports>0 and 'admin_state_up' in network
551 # and network['admin_state_up'] != network_old[0]['admin_state_up']:
553 r
, c
= self
.config
['of_thread'].insert_task("update-net", network_id
)
555 raise ovimException("Error while launching openflow rules %s" % c
, HTTP_Internal_Server_Error
)
556 if self
.config
.get("dhcp_server"):
557 if network_id
in self
.config
["dhcp_nets"]:
558 self
.config
["dhcp_nets"].remove(network_id
)
559 if network
.get("name", network_old
["name"]) in self
.config
["dhcp_server"].get("nets", ()):
560 self
.config
["dhcp_nets"].append(network_id
)
562 net_bind
= network
.get("bind", network_old
["bind"])
563 if net_bind
and net_bind
[:7] == "bridge:" and net_bind
[7:] in self
.config
["dhcp_server"].get(
564 "bridge_ifaces", ()):
565 self
.config
["dhcp_nets"].append(network_id
)
568 raise ovimException(content
, -result
)
570 def delete_network(self
, network_id
):
572 # delete from the data base
573 result
, content
= self
.db
.delete_row('nets', network_id
)
576 raise ovimException("Network %s not found " % network_id
, HTTP_Not_Found
)
578 for brnet
in self
.config
['bridge_nets']:
579 if brnet
[3] == network_id
:
582 if self
.config
.get("dhcp_server") and network_id
in self
.config
["dhcp_nets"]:
583 self
.config
["dhcp_nets"].remove(network_id
)
586 raise ovimException("Error deleting network %s" % network_id
, HTTP_Internal_Server_Error
)
588 def get_openflow_rules(self
, network_id
=None):
590 Get openflow id from DB
591 :param network_id: Network id, if none all networks will be retrieved
592 :return: Return a list with Openflow rules per net
598 where_
= {"net_id": network_id
}
600 result
, content
= self
.db
.get_table(
601 SELECT
=("name", "net_id", "priority", "vlan_id", "ingress_port", "src_mac", "dst_mac", "actions"),
602 WHERE
=where_
, FROM
='of_flows')
605 raise ovimException(str(content
), -result
)
608 def edit_openflow_rules(self
, network_id
=None):
611 To make actions over the net. The action is to reinstall the openflow rules
612 network_id can be 'all'
613 :param network_id: Network id, if none all networks will be retrieved
614 :return : Number of nets updated
621 where_
= {"uuid": network_id
}
622 result
, content
= self
.db
.get_table(SELECT
=("uuid", "type"), WHERE
=where_
, FROM
='nets')
625 raise ovimException(str(content
), -result
)
628 if net
["type"] != "ptp" and net
["type"] != "data":
631 r
, c
= self
.config
['of_thread'].insert_task("update-net", net
['uuid'])
633 raise ovimException(str(c
), -r
)
636 def delete_openflow_rules(self
):
638 To make actions over the net. The action is to delete ALL openflow rules
639 :return: return operation result
642 r
, c
= self
.config
['of_thread'].insert_task("clear-all")
644 raise ovimException(str(c
), -r
)
647 def get_openflow_ports(self
):
649 Obtain switch ports names of openflow controller
650 :return: Return flow ports in DB
652 data
= {'ports': self
.config
['of_thread'].OF_connector
.pp2ofi
}
655 def get_ports(self
, columns
=None, filter={}, limit
=None):
656 # result, content = my.db.get_ports(where_)
657 result
, content
= self
.db
.get_table(SELECT
=columns
, WHERE
=filter, FROM
='ports', LIMIT
=limit
)
659 self
.logger
.error("http_get_ports Error %d %s", result
, content
)
660 raise ovimException(str(content
), -result
)
662 convert_boolean(content
, ('admin_state_up',))
665 def new_port(self
, port_data
):
666 port_data
['type'] = 'external'
667 if port_data
.get('net_id'):
668 # check that new net has the correct type
669 result
, new_net
= self
.db
.check_target_net(port_data
['net_id'], None, 'external')
671 raise ovimException(str(new_net
), -result
)
672 # insert in data base
673 result
, uuid
= self
.db
.new_row('ports', port_data
, True, True)
675 if 'net_id' in port_data
:
676 r
, c
= self
.config
['of_thread'].insert_task("update-net", port_data
['net_id'])
678 self
.logger
.error("Cannot insert a task for updating network '$s' %s", port_data
['net_id'], c
)
679 #TODO put network in error status
682 raise ovimException(str(uuid
), -result
)
684 def delete_port(self
, port_id
):
685 # Look for the previous port data
686 result
, ports
= self
.db
.get_table(WHERE
={'uuid': port_id
, "type": "external"}, FROM
='ports')
688 raise ovimException("Cannot get port info from database: {}".format(ports
), http_code
=-result
)
689 # delete from the data base
690 result
, content
= self
.db
.delete_row('ports', port_id
)
692 raise ovimException("External port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
694 raise ovimException("Cannot delete port from database: {}".format(content
), http_code
=-result
)
696 network
= ports
[0].get('net_id', None)
699 r
, c
= self
.config
['of_thread'].insert_task("update-net", network
)
701 self
.logger
.error("Cannot insert a task for updating network '$s' %s", network
, c
)
704 def edit_port(self
, port_id
, port_data
, admin
=True):
705 # Look for the previous port data
706 result
, content
= self
.db
.get_table(FROM
="ports", WHERE
={'uuid': port_id
})
708 raise ovimException("Cannot get port info from database: {}".format(content
), http_code
=-result
)
710 raise ovimException("Port '{}' not found".format(port_id
), http_code
=HTTP_Not_Found
)
715 if 'net_id' in port_data
:
717 old_net
= port
.get('net_id', None)
718 new_net
= port_data
['net_id']
719 if old_net
!= new_net
:
722 nets
.append(new_net
) # put first the new net, so that new openflow rules are created before removing the old ones
725 if port
['type'] == 'instance:bridge' or port
['type'] == 'instance:ovs':
726 raise ovimException("bridge interfaces cannot be attached to a different net", http_code
=HTTP_Forbidden
)
727 elif port
['type'] == 'external' and not admin
:
728 raise ovimException("Needed admin privileges",http_code
=HTTP_Unauthorized
)
730 # check that new net has the correct type
731 result
, new_net_dict
= self
.db
.check_target_net(new_net
, None, port
['type'])
733 raise ovimException("Error {}".format(new_net_dict
), http_code
=HTTP_Conflict
)
734 # change VLAN for SR-IOV ports
735 if result
>= 0 and port
["type"] == "instance:data" and port
["model"] == "VF": # TODO consider also VFnotShared
737 port_data
["vlan"] = None
739 port_data
["vlan"] = new_net_dict
["vlan"]
740 # get host where this VM is allocated
741 result
, content
= self
.db
.get_table(FROM
="instances", WHERE
={"uuid": port
["instance_id"]})
743 host_id
= content
[0]["host_id"]
745 # insert in data base
747 result
, content
= self
.db
.update_rows('ports', port_data
, WHERE
={'uuid': port_id
}, log
=False)
749 # Insert task to complete actions
752 r
, v
= self
.config
['of_thread'].insert_task("update-net", net_id
)
754 self
.logger
.error("Error updating network '{}' {}".format(r
,v
))
755 # TODO Do something if fails
757 r
, v
= self
.config
['host_threads'][host_id
].insert_task("edit-iface", port_id
, old_net
, new_net
)
759 self
.logger
.error("Error updating network '{}' {}".format(r
,v
))
760 # TODO Do something if fails
764 raise ovimException("Error {}".format(content
), http_code
=-result
)
766 def get_dhcp_controller(self
):
768 Create an host_thread object for manage openvim controller and not create a thread for itself
769 :return: dhcp_host openvim controller object
772 if 'openvim_controller' in self
.config
['host_threads']:
773 return self
.config
['host_threads']['openvim_controller']
776 controller_ip
= self
.config
['ovs_controller_ip']
777 ovs_controller_user
= self
.config
['ovs_controller_user']
779 host_test_mode
= True if self
.config
['mode'] == 'test' or self
.config
['mode'] == "OF only" else False
780 host_develop_mode
= True if self
.config
['mode'] == 'development' else False
782 dhcp_host
= ht
.host_thread(name
='openvim_controller', user
=ovs_controller_user
, host
=controller_ip
,
783 db
=self
.config
['db'],
784 db_lock
=self
.config
['db_lock'], test
=host_test_mode
,
785 image_path
=self
.config
['image_path'], version
=self
.config
['version'],
786 host_id
='openvim_controller', develop_mode
=host_develop_mode
,
787 develop_bridge_iface
=bridge_ifaces
)
789 self
.config
['host_threads']['openvim_controller'] = dhcp_host
790 if not host_test_mode
:
791 dhcp_host
.ssh_connect()
794 def launch_dhcp_server(self
, vlan
, first_ip
, last_ip
, cidr
, gateway
):
796 Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
797 :param vlan: vlan identifier
798 :param first_ip: First dhcp range ip
799 :param last_ip: Last dhcp range ip
800 :param cidr: net cidr
801 :param gateway: net gateway
804 ip_tools
= IPNetwork(cidr
)
805 dhcp_netmask
= str(ip_tools
.netmask
)
806 ip_range
= [first_ip
, last_ip
]
808 dhcp_path
= self
.config
['ovs_controller_file_path']
810 controller_host
= self
.get_dhcp_controller()
811 controller_host
.create_linux_bridge(vlan
)
812 controller_host
.create_dhcp_interfaces(vlan
, first_ip
, dhcp_netmask
)
813 controller_host
.launch_dhcp_server(vlan
, ip_range
, dhcp_netmask
, dhcp_path
, gateway
)