X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=httpserver.py;h=1237fb4da73dcaac6b5e112a50e92c96f11691fe;hb=c1d1d47cee5bd382fd9e2ca4d829aef0f545a0d1;hp=ce433aed7268908d4934561fa4172dbebf0f4bf6;hpb=69a5739aef6bdc5e0ebc12ebfe6a4775e8211304;p=osm%2Fopenvim.git diff --git a/httpserver.py b/httpserver.py index ce433ae..1237fb4 100644 --- a/httpserver.py +++ b/httpserver.py @@ -26,7 +26,7 @@ This is the thread for the http server North API. Two thread will be launched, with normal and administrative permissions. ''' -__author__="Alfonso Tierno" +__author__="Alfonso Tierno, Gerardo Garcia, Leonardo Mirabal" __date__ ="$10-jul-2014 12:07:15$" import bottle @@ -38,6 +38,7 @@ import datetime import hashlib import os import imp +from netaddr import IPNetwork, IPAddress, all_matching_cidrs #import only if needed because not needed in test mode. To allow an easier installation import RADclass from jsonschema import validate as js_v, exceptions as js_e import host_thread as ht @@ -74,6 +75,11 @@ def md5(fname): hash_md5.update(chunk) return hash_md5.hexdigest() +def md5_string(fname): + hash_md5 = hashlib.md5() + hash_md5.update(fname) + return hash_md5.hexdigest() + def check_extended(extended, allow_net_attach=False): '''Makes and extra checking of extended input that cannot be done using jsonschema Attributes: @@ -492,8 +498,12 @@ def enable_cors(): @bottle.route(url_base + '/hosts', method='GET') def http_get_hosts(): - select_,where_,limit_ = filter_query_string(bottle.request.query, http2db_host, - ('id','name','description','status','admin_state_up') ) + return format_out(get_hosts()) + + +def get_hosts(): + select_, where_, limit_ = filter_query_string(bottle.request.query, http2db_host, + ('id', 'name', 'description', 'status', 'admin_state_up', 'ip_name')) myself = config_dic['http_threads'][ threading.current_thread().name ] result, content = myself.db.get_table(FROM='hosts', SELECT=select_, WHERE=where_, LIMIT=limit_) @@ -506,7 +516,7 @@ def http_get_hosts(): for row in content: row['links'] = ( {'href': myself.url_preffix + '/hosts/' + str(row['id']), 'rel': 'bookmark'}, ) data={'hosts' : content} - return format_out(data) + return data @bottle.route(url_base + '/hosts/', method='GET') def http_get_host_id(host_id): @@ -628,6 +638,13 @@ def http_post_hosts(): thread.start() config_dic['host_threads'][ content['uuid'] ] = thread + if config_dic['network_type'] == 'ovs': + # create bridge + create_dhcp_ovs_bridge() + config_dic['host_threads'][content['uuid']].insert_task("new-ovsbridge") + # check if more host exist + create_vxlan_mesh(content['uuid']) + #return host data change_keys_http2db(content, http2db_host, reverse=True) if len(warning_text)>0: @@ -638,6 +655,180 @@ def http_post_hosts(): bottle.abort(HTTP_Bad_Request, content) return + +def get_dhcp_controller(): + """ + Create an host_thread object for manage openvim controller and not create a thread for itself + :return: dhcp_host openvim controller object + """ + + if 'openvim_controller' in config_dic['host_threads']: + return config_dic['host_threads']['openvim_controller'] + + bridge_ifaces = [] + controller_ip = config_dic['ovs_controller_ip'] + ovs_controller_user = config_dic['ovs_controller_user'] + + host_test_mode = True if config_dic['mode'] == 'test' or config_dic['mode'] == "OF only" else False + host_develop_mode = True if config_dic['mode'] == 'development' else False + + dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip, db=config_dic['db'], + db_lock=config_dic['db_lock'], test=host_test_mode, + image_path=config_dic['image_path'], version=config_dic['version'], + host_id='openvim_controller', develop_mode=host_develop_mode, + develop_bridge_iface=bridge_ifaces) + + config_dic['host_threads']['openvim_controller'] = dhcp_host + dhcp_host.ssh_connect() + return dhcp_host + + +def delete_dhcp_ovs_bridge(vlan, net_uuid): + """ + Delete bridges and port created during dhcp launching at openvim controller + :param vlan: net vlan id + :param net_uuid: network identifier + :return: + """ + dhcp_path = config_dic['ovs_controller_file_path'] + + controller_host = get_dhcp_controller() + controller_host.delete_dhcp_port(vlan, net_uuid) + controller_host.delete_dhcp_server(vlan, net_uuid, dhcp_path) + + +def create_dhcp_ovs_bridge(): + """ + Initialize bridge to allocate the dhcp server at openvim controller + :return: + """ + controller_host = get_dhcp_controller() + controller_host.create_ovs_bridge() + + +def set_mac_dhcp(vm_ip, vlan, first_ip, last_ip, cidr, mac): + """" + Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes + :param vm_ip: IP address asigned to a VM + :param vlan: Segmentation id + :param first_ip: First dhcp range ip + :param last_ip: Last dhcp range ip + :param cidr: net cidr + :param mac: VM vnic mac to be macthed with the IP received + """ + if not vm_ip: + return + ip_tools = IPNetwork(cidr) + cidr_len = ip_tools.prefixlen + dhcp_netmask = str(ip_tools.netmask) + dhcp_path = config_dic['ovs_controller_file_path'] + + new_cidr = [first_ip + '/' + str(cidr_len)] + if not len(all_matching_cidrs(vm_ip, new_cidr)): + vm_ip = None + + controller_host = get_dhcp_controller() + controller_host.set_mac_dhcp_server(vm_ip, mac, vlan, dhcp_netmask, dhcp_path) + + +def delete_mac_dhcp(vm_ip, vlan, mac): + """ + Delete into dhcp conf file the ip assigned to a specific MAC address + :param vm_ip: IP address asigned to a VM + :param vlan: Segmentation id + :param mac: VM vnic mac to be macthed with the IP received + :return: + """ + + dhcp_path = config_dic['ovs_controller_file_path'] + + controller_host = get_dhcp_controller() + controller_host.delete_mac_dhcp_server(vm_ip, mac, vlan, dhcp_path) + + +def launch_dhcp_server(vlan, first_ip, last_ip, cidr): + """ + Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes + :param vlan: vlan identifier + :param first_ip: First dhcp range ip + :param last_ip: Last dhcp range ip + :param cidr: net cidr + :return: + """ + ip_tools = IPNetwork(cidr) + dhcp_netmask = str(ip_tools.netmask) + ip_range = [first_ip, last_ip] + dhcp_path = config_dic['ovs_controller_file_path'] + + controller_host = get_dhcp_controller() + controller_host.create_linux_bridge(vlan) + controller_host.create_dhcp_interfaces(vlan, first_ip, dhcp_netmask) + controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path) + + +def create_vxlan_mesh(host_id): + """ + Create vxlan mesh across all openvimc controller and computes. + :param host_id: host identifier + :param host_id: host identifier + :return: + """ + dhcp_compute_name = get_vxlan_interface("dhcp") + existing_hosts = get_hosts() + if len(existing_hosts['hosts']) > 0: + # vlxan mesh creation between openvim controller and computes + computes_available = existing_hosts['hosts'] + controller_host = get_dhcp_controller() + for compute in computes_available: + vxlan_interface_name = get_vxlan_interface(compute['id'][:8]) + config_dic['host_threads'][compute['id']].insert_task("new-vxlan", dhcp_compute_name, controller_host.host) + controller_host.create_ovs_vxlan_tunnel(vxlan_interface_name, compute['ip_name']) + + # vlxan mesh creation between openvim computes + for count, compute_owner in enumerate(computes_available): + for compute in computes_available: + if compute_owner['id'] == compute['id']: + pass + else: + vxlan_interface_name = get_vxlan_interface(compute_owner['id'][:8]) + controller_host.create_ovs_vxlan_tunnel(vxlan_interface_name, compute_owner['ip_name']) + config_dic['host_threads'][compute['id']].insert_task("new-vxlan", + vxlan_interface_name, + compute_owner['ip_name']) + + +def delete_vxlan_mesh(host_id): + """ + Create a task for remove a specific compute of the vlxan mesh + :param host_id: host id to be deleted. + """ + existing_hosts = get_hosts() + computes_available = existing_hosts['hosts'] + # + vxlan_interface_name = get_vxlan_interface(host_id[:8]) + controller_host = get_dhcp_controller() + controller_host.delete_ovs_vxlan_tunnel(vxlan_interface_name) + # remove bridge from openvim controller if no more computes exist + if len(existing_hosts): + controller_host.delete_ovs_bridge() + # Remove vxlan mesh + for compute in computes_available: + if host_id == compute['id']: + pass + else: + controller_host.delete_ovs_vxlan_tunnel(vxlan_interface_name) + config_dic['host_threads'][compute['id']].insert_task("del-vxlan", vxlan_interface_name) + + +def get_vxlan_interface(local_uuid): + """ + Genearte a vxlan interface name + :param local_uuid: host id + :return: vlxan-8digits + """ + return 'vxlan-' + local_uuid[:8] + + @bottle.route(url_base + '/hosts/', method='PUT') def http_put_host_id(host_id): '''modify a host into the database. All resources are got and inserted''' @@ -659,12 +850,21 @@ def http_put_host_id(host_id): change_keys_http2db(content, http2db_host, reverse=True) data={'host' : content} + if config_dic['network_type'] == 'ovs': + delete_vxlan_mesh(host_id) + config_dic['host_threads'][host_id].insert_task("del-ovsbridge") + #reload thread config_dic['host_threads'][host_id].name = content.get('name',content['ip_name']) config_dic['host_threads'][host_id].user = content['user'] config_dic['host_threads'][host_id].host = content['ip_name'] config_dic['host_threads'][host_id].insert_task("reload") + if config_dic['network_type'] == 'ovs': + # create mesh with new host data + config_dic['host_threads'][host_id].insert_task("new-ovsbridge") + create_vxlan_mesh(host_id) + #print data return format_out(data) else: @@ -682,9 +882,13 @@ def http_delete_host_id(host_id): result, content = my.db.delete_row('hosts', host_id) if result == 0: bottle.abort(HTTP_Not_Found, content) - elif result >0: - #terminate thread + elif result > 0: + if config_dic['network_type'] == 'ovs': + delete_vxlan_mesh(host_id) + # terminate thread if host_id in config_dic['host_threads']: + if config_dic['network_type'] == 'ovs': + config_dic['host_threads'][host_id].insert_task("del-ovsbridge") config_dic['host_threads'][host_id].insert_task("exit") #return data data={'result' : content} @@ -1039,14 +1243,14 @@ def http_get_images(tenant_id): bottle.abort(result, content) #obtain data select_,where_,limit_ = filter_query_string(bottle.request.query, http2db_image, - ('id','name','description','path','public') ) + ('id','name','checksum','description','path','public') ) if tenant_id=='any': from_ ='images' where_or_ = None else: from_ ='tenants_images right join images on tenants_images.image_id=images.uuid' where_or_ = {'tenant_id': tenant_id, 'public': 'yes'} - result, content = my.db.get_table(SELECT=select_, FROM=from_, WHERE=where_, WHERE_OR=where_or_, WHERE_AND_OR="AND", LIMIT=limit_) + result, content = my.db.get_table(SELECT=select_, DISTINCT=True, FROM=from_, WHERE=where_, WHERE_OR=where_or_, WHERE_AND_OR="AND", LIMIT=limit_) if result < 0: print "http_get_images Error", content bottle.abort(-result, content) @@ -1065,7 +1269,7 @@ def http_get_image_id(tenant_id, image_id): bottle.abort(result, content) #obtain data select_,where_,limit_ = filter_query_string(bottle.request.query, http2db_image, - ('id','name','description','progress', 'status','path', 'created', 'updated','public') ) + ('id','name','checksum','description','progress', 'status','path', 'created', 'updated','public') ) if tenant_id=='any': from_ ='images' where_or_ = None @@ -1073,7 +1277,7 @@ def http_get_image_id(tenant_id, image_id): from_ ='tenants_images as ti right join images as i on ti.image_id=i.uuid' where_or_ = {'tenant_id': tenant_id, 'public': "yes"} where_['uuid'] = image_id - result, content = my.db.get_table(SELECT=select_, FROM=from_, WHERE=where_, WHERE_OR=where_or_, WHERE_AND_OR="AND", LIMIT=limit_) + result, content = my.db.get_table(SELECT=select_, DISTINCT=True, FROM=from_, WHERE=where_, WHERE_OR=where_or_, WHERE_AND_OR="AND", LIMIT=limit_) if result < 0: print "http_get_images error %d %s" % (result, content) @@ -1108,15 +1312,26 @@ def http_post_images(tenant_id): if metadata_dict is not None: http_content['image']['metadata'] = json.dumps(metadata_dict) #calculate checksum - host_test_mode = True if config_dic['mode']=='test' or config_dic['mode']=="OF only" else False try: image_file = http_content['image'].get('path',None) - if os.path.exists(image_file): - http_content['image']['checksum'] = md5(image_file) - elif is_url(image_file): + parsed_url = urlparse.urlparse(image_file) + if parsed_url.scheme == "" and parsed_url.netloc == "": + # The path is a local file + if os.path.exists(image_file): + http_content['image']['checksum'] = md5(image_file) + else: + # The path is a URL. Code should be added to download the image and calculate the checksum + #http_content['image']['checksum'] = md5(downloaded_image) pass + # Finally, only if we are in test mode and checksum has not been calculated, we calculate it from the path + host_test_mode = True if config_dic['mode']=='test' or config_dic['mode']=="OF only" else False + if host_test_mode: + if 'checksum' not in http_content['image']: + http_content['image']['checksum'] = md5_string(image_file) else: - if not host_test_mode: + # At this point, if the path is a local file and no chechsum has been obtained yet, an error is sent back. + # If it is a URL, no error is sent. Checksum will be an empty string + if parsed_url.scheme == "" and parsed_url.netloc == "" and 'checksum' not in http_content['image']: content = "Image file not found" print "http_post_images error: %d %s" % (HTTP_Bad_Request, content) bottle.abort(HTTP_Bad_Request, content) @@ -1227,10 +1442,11 @@ def http_put_image_id(tenant_id, image_id): where_={'uuid': image_id} if tenant_id=='any': from_ ='images' + where_or_ = None else: - from_ ='tenants_images as ti inner join images as i on ti.image_id=i.uuid' - where_['tenant_id'] = tenant_id - result, content = my.db.get_table(SELECT=('public',), FROM=from_, WHERE=where_) + from_ ='tenants_images as ti right join images as i on ti.image_id=i.uuid' + where_or_ = {'tenant_id': tenant_id, 'public': 'yes'} + result, content = my.db.get_table(SELECT=('public',), DISTINCT=True, FROM=from_, WHERE=where_, WHERE_OR=where_or_, WHERE_AND_OR="AND") if result==0: text_error="Image '%s' not found" % image_id if tenant_id!='any': @@ -1358,12 +1574,25 @@ def http_post_server_id(tenant_id): return server['flavor']=content[0] #check image valid and take info - result, content = my.db.get_table(FROM='tenants_images as ti join images as i on ti.image_id=i.uuid', - SELECT=('path','metadata'), WHERE={'uuid':server['image_id'], 'tenant_id':tenant_id, "status":"ACTIVE"}) + result, content = my.db.get_table(FROM='tenants_images as ti right join images as i on ti.image_id=i.uuid', + SELECT=('path', 'metadata', 'image_id'), + WHERE={'uuid':server['image_id'], "status":"ACTIVE"}, + WHERE_OR={'tenant_id':tenant_id, 'public': 'yes'}, + WHERE_AND_OR="AND", + DISTINCT=True) if result<=0: bottle.abort(HTTP_Not_Found, 'image_id %s not found or not ACTIVE' % server['image_id']) return - server['image']=content[0] + for image_dict in content: + if image_dict.get("image_id"): + break + else: + # insert in data base tenants_images + r2, c2 = my.db.new_row('tenants_images', {'image_id': server['image_id'], 'tenant_id': tenant_id}) + if r2<=0: + bottle.abort(HTTP_Not_Found, 'image_id %s cannot be used. Error %s' % (server['image_id'], c2)) + return + server['image']={"path": content[0]["path"], "metadata": content[0]["metadata"]} if "hosts_id" in server: result, content = my.db.get_table(FROM='hosts', SELECT=('uuid',), WHERE={'uuid': server['host_id']}) if result<=0: @@ -1381,6 +1610,11 @@ def http_post_server_id(tenant_id): print if server_start == 'no': content['status'] = 'INACTIVE' + dhcp_nets_id = [] + for net in http_content['server']['networks']: + if net['type'] == 'instance:ovs': + dhcp_nets_id.append(get_network_id(net['net_id'])) + ports_to_free=[] new_instance_result, new_instance = my.db.new_instance(content, nets, ports_to_free) if new_instance_result < 0: @@ -1401,23 +1635,37 @@ def http_post_server_id(tenant_id): print ':http_post_servers ERROR UPDATING NETS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c - - #look for dhcp ip address - r2, c2 = my.db.get_table(FROM="ports", SELECT=["mac", "net_id"], WHERE={"instance_id": new_instance}) - if r2 >0 and config_dic.get("dhcp_server"): + #look for dhcp ip address + r2, c2 = my.db.get_table(FROM="ports", SELECT=["mac", "ip_address", "net_id"], WHERE={"instance_id": new_instance}) + if r2 >0: for iface in c2: - if iface["net_id"] in config_dic["dhcp_nets"]: + if config_dic.get("dhcp_server") and iface["net_id"] in config_dic["dhcp_nets"]: #print "dhcp insert add task" r,c = config_dic['dhcp_thread'].insert_task("add", iface["mac"]) if r < 0: - print ':http_post_servers ERROR UPDATING dhcp_server !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c - - #Start server - + print ':http_post_servers ERROR UPDATING dhcp_server !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c + + #ensure compute contain the bridge for ovs networks: + server_net = get_network_id(iface['net_id']) + if server_net["network"].get('provider:physical', "")[:3] == 'OVS': + vlan = str(server_net['network']['provider:vlan']) + dhcp_enable = bool(server_net['network']['enable_dhcp']) + if dhcp_enable: + dhcp_firt_ip = str(server_net['network']['dhcp_first_ip']) + dhcp_last_ip = str(server_net['network']['dhcp_last_ip']) + dhcp_cidr = str(server_net['network']['cidr']) + vm_dhcp_ip = c2[0]["ip_address"] + config_dic['host_threads'][server['host_id']].insert_task("create-ovs-bridge-port", vlan) + + set_mac_dhcp(vm_dhcp_ip, vlan, dhcp_firt_ip, dhcp_last_ip, dhcp_cidr, c2[0]['mac']) + launch_dhcp_server(vlan, dhcp_firt_ip, dhcp_last_ip, dhcp_cidr) + + #Start server server['uuid'] = new_instance - #server_start = server.get('start', 'yes') + server_start = server.get('start', 'yes') + if server_start != 'no': - server['paused'] = True if server_start == 'paused' else False + server['paused'] = True if server_start == 'paused' else False server['action'] = {"start":None} server['status'] = "CREATING" #Program task @@ -1501,8 +1749,9 @@ def http_server_action(server_id, tenant_id, action): else: #result==1 image_id = content[0]['image_id'] - result, content = my.db.get_table(FROM='tenants_images as ti join images as i on ti.image_id=i.uuid', - SELECT=('path','metadata'), WHERE={'uuid':image_id, 'tenant_id':tenant_id, "status":"ACTIVE"}) + result, content = my.db.get_table(FROM='tenants_images as ti right join images as i on ti.image_id=i.uuid', + SELECT=('path','metadata'), WHERE={'uuid':image_id, "status":"ACTIVE"}, + WHERE_OR={'tenant_id':tenant_id, 'public': 'yes'}, WHERE_AND_OR="AND", DISTINCT=True) if result<=0: bottle.abort(HTTP_Not_Found, 'image_id %s not found or not ACTIVE' % image_id) return @@ -1554,9 +1803,11 @@ def http_server_action(server_id, tenant_id, action): if new_status != None and new_status == 'DELETING': nets=[] ports_to_free=[] - #look for dhcp ip address + + net_ovs_list = [] + #look for dhcp ip address r2, c2 = my.db.get_table(FROM="ports", SELECT=["mac", "net_id"], WHERE={"instance_id": server_id}) - r,c = my.db.delete_instance(server_id, tenant_id, nets, ports_to_free, "requested by http") + r, c = my.db.delete_instance(server_id, tenant_id, nets, ports_to_free, net_ovs_list, "requested by http") for port in ports_to_free: r1,c1 = config_dic['host_threads'][ server['host_id'] ].insert_task( 'restore-iface',*port ) if r1 < 0: @@ -1575,7 +1826,15 @@ def http_server_action(server_id, tenant_id, action): #print "dhcp insert del task" if r < 0: print ':http_post_servers ERROR UPDATING dhcp_server !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c - + # delete ovs-port and linux bridge, contains a list of tuple (net_id,vlan) + for net in net_ovs_list: + mac = str(net[3]) + vm_ip = str(net[2]) + vlan = str(net[1]) + net_id = net[0] + delete_dhcp_ovs_bridge(vlan, net_id) + delete_mac_dhcp(vm_ip, vlan, mac) + config_dic['host_threads'][server['host_id']].insert_task('del-ovs-port', vlan, net_id) return format_out(data) @@ -1628,7 +1887,7 @@ def http_get_networks(): print "http_get_networks error %d %s" % (result, content) bottle.abort(-result, content) else: - convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp') ) + convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp')) delete_nulls(content) change_keys_http2db(content, http2db_network, reverse=True) data={'networks' : content} @@ -1636,8 +1895,12 @@ def http_get_networks(): @bottle.route(url_base + '/networks/', method='GET') def http_get_network_id(network_id): - my = config_dic['http_threads'][ threading.current_thread().name ] - #obtain data + data = get_network_id(network_id) + return format_out(data) + +def get_network_id(network_id): + my = config_dic['http_threads'][threading.current_thread().name] + # obtain data where_ = bottle.request.query where_['uuid'] = network_id result, content = my.db.get_table(FROM='nets', WHERE=where_, LIMIT=100) @@ -1649,7 +1912,7 @@ def http_get_network_id(network_id): print "http_get_networks_id network '%s' not found" % network_id bottle.abort(HTTP_Not_Found, 'network %s not found' % network_id) else: - convert_boolean(content, ('shared', 'admin_state_up', 'enale_dhcp') ) + convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp')) change_keys_http2db(content, http2db_network, reverse=True) #get ports result, ports = my.db.get_table(FROM='ports', SELECT=('uuid as port_id',), @@ -1658,7 +1921,7 @@ def http_get_network_id(network_id): content[0]['ports'] = ports delete_nulls(content[0]) data={'network' : content[0]} - return format_out(data) + return data @bottle.route(url_base + '/networks', method='POST') def http_post_networks(): @@ -1681,6 +1944,10 @@ def http_post_networks(): #check valid params net_provider = network.get('provider') net_type = network.get('type') + net_enable_dhcp = network.get('enable_dhcp') + if net_enable_dhcp: + net_cidr = network.get('cidr') + net_vlan = network.get("vlan") net_bind_net = network.get("bind_net") net_bind_type= network.get("bind_type") @@ -1755,7 +2022,7 @@ def http_post_networks(): # if bridge_net==None: # bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name) # return - elif net_type=='bridge_data' or net_type=='bridge_man': + elif config_dic['network_type'] == 'bridge' and ( net_type =='bridge_data' or net_type == 'bridge_man' ): #look for a free precreated nets for brnet in config_dic['bridge_nets']: if brnet[3]==None: # free @@ -1774,22 +2041,29 @@ def http_post_networks(): print "using net", bridge_net net_provider = "bridge:"+bridge_net[0] net_vlan = bridge_net[1] - if net_vlan==None and (net_type=="data" or net_type=="ptp"): + elif net_type == 'bridge_data' or net_type == 'bridge_man' and config_dic['network_type'] == 'ovs': + net_provider = 'OVS' + if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"): net_vlan = my.db.get_free_net_vlan() if net_vlan < 0: bottle.abort(HTTP_Internal_Server_Error, "Error getting an available vlan") return - + if net_provider == 'OVS': + net_provider = 'OVS' + ":" + str(net_vlan) + network['provider'] = net_provider network['type'] = net_type network['vlan'] = net_vlan + + if 'enable_dhcp' in network and network['enable_dhcp']: + check_dhcp_data_integrity(network) + result, content = my.db.new_row('nets', network, True, True) if result >= 0: if bridge_net!=None: bridge_net[3] = content - - if config_dic.get("dhcp_server"): + if config_dic.get("dhcp_server") and config_dic['network_type'] == 'bridge': if network["name"] in config_dic["dhcp_server"].get("nets", () ): config_dic["dhcp_nets"].append(content) print "dhcp_server: add new net", content @@ -1803,6 +2077,24 @@ def http_post_networks(): return +def check_dhcp_data_integrity(network): + """ + Check if all dhcp parameter for anet are valid, if not will be calculated from cidr value + :param network: list with user nets paramters + :return: + """ + control_iface = [] + + if "cidr" in network: + cidr = network["cidr"] + + ips = IPNetwork(cidr) + if "dhcp_first_ip" not in network: + network["dhcp_first_ip"] = str(ips[2]) + if "dhcp_last_ip" not in network: + network["dhcp_last_ip"] = str(ips[-2]) + + @bottle.route(url_base + '/networks/', method='PUT') def http_put_network_id(network_id): '''update a network_id into the database.''' @@ -2121,7 +2413,7 @@ def http_put_port_id(port_id): if new_net is not None: nets.append(new_net) #put first the new net, so that new openflow rules are created before removing the old ones if old_net is not None: nets.append(old_net) - if port['type'] == 'instance:bridge': + if port['type'] == 'instance:bridge' or port['type'] == 'instance:ovs': bottle.abort(HTTP_Forbidden, "bridge interfaces cannot be attached to a different net") return elif port['type'] == 'external':