X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=httpserver.py;h=edf1e8d9183e45ce8360a34ba43900bf091dd529;hb=refs%2Fchanges%2F17%2F1317%2F3;hp=c8d093f1ccf1c6029db131641eae21ca202802e0;hpb=b716ac5bed1d8887750f1ceb97cbe8f8839fbfa8;p=osm%2Fopenvim.git diff --git a/httpserver.py b/httpserver.py index c8d093f..edf1e8d 100644 --- a/httpserver.py +++ b/httpserver.py @@ -47,7 +47,7 @@ from vim_schema import host_new_schema, host_edit_schema, tenant_new_schema, \ flavor_new_schema, flavor_update_schema, \ image_new_schema, image_update_schema, \ server_new_schema, server_action_schema, network_new_schema, network_update_schema, \ - port_new_schema, port_update_schema + port_new_schema, port_update_schema, openflow_controller_schema, of_port_map_new_schema import ovim import logging @@ -147,12 +147,14 @@ def check_extended(extended, allow_net_attach=False): # # dictionaries that change from HTTP API to database naming # +http2db_id={'id':'uuid'} http2db_host={'id':'uuid'} http2db_tenant={'id':'uuid'} http2db_flavor={'id':'uuid','imageRef':'image_id'} http2db_image={'id':'uuid', 'created':'created_at', 'updated':'modified_at', 'public': 'public'} http2db_server={'id':'uuid','hostId':'host_id','flavorRef':'flavor_id','imageRef':'image_id','created':'created_at'} http2db_network={'id':'uuid','provider:vlan':'vlan', 'provider:physical': 'provider'} +http2db_ofc = {'id': 'uuid'} http2db_port={'id':'uuid', 'network_id':'net_id', 'mac_address':'mac', 'device_owner':'type','device_id':'instance_id','binding:switch_port':'switch_port','binding:vlan':'vlan', 'bandwidth':'Mbps'} def remove_extra_items(data, schema): @@ -458,15 +460,6 @@ def check_valid_tenant(my, tenant_id): return HTTP_Not_Found, "tenant '%s' not found" % tenant_id return 0, None -def check_valid_uuid(uuid): - id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"} - try: - js_v(uuid, id_schema) - return True - except js_e.ValidationError: - return False - - def is_url(url): ''' Check if string value is a well-wormed url @@ -869,114 +862,140 @@ def http_delete_host_id(host_id): print "http_delete_host_id error",result, content bottle.abort(-result, content) return - - - # # TENANTS # + @bottle.route(url_base + '/tenants', method='GET') def http_get_tenants(): - my = config_dic['http_threads'][ threading.current_thread().name ] - select_,where_,limit_ = filter_query_string(bottle.request.query, http2db_tenant, - ('id','name','description','enabled') ) - result, content = my.db.get_table(FROM='tenants', SELECT=select_,WHERE=where_,LIMIT=limit_) - if result < 0: - print "http_get_tenants Error", content - bottle.abort(-result, content) - else: - change_keys_http2db(content, http2db_tenant, reverse=True) - convert_boolean(content, ('enabled',)) - data={'tenants' : content} - #data['tenants_links'] = dict([('tenant', row['id']) for row in content]) + """ + Retreive tenant list from DB + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + select_, where_, limit_ = filter_query_string(bottle.request.query, http2db_tenant, + ('id', 'name', 'description', 'enabled')) + tenants = my.ovim.get_tenants(select_, where_) + delete_nulls(tenants) + change_keys_http2db(tenants, http2db_tenant, reverse=True) + data = {'tenants': tenants} return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + @bottle.route(url_base + '/tenants/', method='GET') def http_get_tenant_id(tenant_id): - my = config_dic['http_threads'][ threading.current_thread().name ] - result, content = my.db.get_table(FROM='tenants', SELECT=('uuid','name','description', 'enabled'),WHERE={'uuid': tenant_id} ) - if result < 0: - print "http_get_tenant_id error %d %s" % (result, content) - bottle.abort(-result, content) - elif result==0: - print "http_get_tenant_id tenant '%s' not found" % tenant_id - bottle.abort(HTTP_Not_Found, "tenant %s not found" % tenant_id) - else: - change_keys_http2db(content, http2db_tenant, reverse=True) - convert_boolean(content, ('enabled',)) - data={'tenant' : content[0]} - #data['tenants_links'] = dict([('tenant', row['id']) for row in content]) + """ + Get tenant from DB by id + :param tenant_id: tenant id + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + tenant = my.ovim.show_tenant_id(tenant_id) + delete_nulls(tenant) + change_keys_http2db(tenant, http2db_tenant, reverse=True) + data = {'tenant': tenant} return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) @bottle.route(url_base + '/tenants', method='POST') def http_post_tenants(): - '''insert a tenant into the database.''' - my = config_dic['http_threads'][ threading.current_thread().name ] - #parse input data - http_content = format_in( tenant_new_schema ) - r = remove_extra_items(http_content, tenant_new_schema) - if r is not None: print "http_post_tenants: Warning: remove extra items ", r - change_keys_http2db(http_content['tenant'], http2db_tenant) + """ + Insert a tenant into the database. + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + http_content = format_in(tenant_new_schema) + r = remove_extra_items(http_content, tenant_new_schema) + if r is not None: + my.logger.error("http_post_tenants: Warning: remove extra items " + str(r), exc_info=True) + # insert in data base + tenant_id = my.ovim.new_tentant(http_content['tenant']) + tenant = my.ovim.show_tenant_id(tenant_id) + change_keys_http2db(tenant, http2db_tenant, reverse=True) + delete_nulls(tenant) + data = {'tenant': tenant} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) - #insert in data base - result, content = my.db.new_tenant(http_content['tenant']) - - if result >= 0: - return http_get_tenant_id(content) - else: - bottle.abort(-result, content) - return @bottle.route(url_base + '/tenants/', method='PUT') def http_put_tenant_id(tenant_id): - '''update a tenant into the database.''' - my = config_dic['http_threads'][ threading.current_thread().name ] - #parse input data - http_content = format_in( tenant_edit_schema ) - r = remove_extra_items(http_content, tenant_edit_schema) - if r is not None: print "http_put_tenant_id: Warning: remove extra items ", r - change_keys_http2db(http_content['tenant'], http2db_tenant) + """ + Update a tenantinto DB. + :param tenant_id: tentant id + :return: + """ + + my = config_dic['http_threads'][threading.current_thread().name] + try: + # parse input data + http_content = format_in(tenant_edit_schema) + r = remove_extra_items(http_content, tenant_edit_schema) + if r is not None: + print "http_put_tenant_id: Warning: remove extra items ", r + change_keys_http2db(http_content['tenant'], http2db_tenant) + # insert in data base + my.ovim.edit_tenant(tenant_id, http_content['tenant']) + tenant = my.ovim.show_tenant_id(tenant_id) + change_keys_http2db(tenant, http2db_tenant, reverse=True) + data = {'tenant': tenant} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) - #insert in data base - result, content = my.db.update_rows('tenants', http_content['tenant'], WHERE={'uuid': tenant_id}, log=True ) - if result >= 0: - return http_get_tenant_id(tenant_id) - else: - bottle.abort(-result, content) - return @bottle.route(url_base + '/tenants/', method='DELETE') def http_delete_tenant_id(tenant_id): - my = config_dic['http_threads'][ threading.current_thread().name ] - #check permissions - r, tenants_flavors = my.db.get_table(FROM='tenants_flavors', SELECT=('flavor_id','tenant_id'), WHERE={'tenant_id': tenant_id}) - if r<=0: - tenants_flavors=() - r, tenants_images = my.db.get_table(FROM='tenants_images', SELECT=('image_id','tenant_id'), WHERE={'tenant_id': tenant_id}) - if r<=0: - tenants_images=() - result, content = my.db.delete_row('tenants', tenant_id) - if result == 0: - bottle.abort(HTTP_Not_Found, content) - elif result >0: - print "alf", tenants_flavors, tenants_images - for flavor in tenants_flavors: - my.db.delete_row_by_key("flavors", "uuid", flavor['flavor_id']) - for image in tenants_images: - my.db.delete_row_by_key("images", "uuid", image['image_id']) - data={'result' : content} - return format_out(data) - else: - print "http_delete_tenant_id error",result, content - bottle.abort(-result, content) - return + """ + Delete a tenant from the database. + :param tenant_id: tenant id + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + try: + content = my.ovim.delete_tentant(tenant_id) + data = {'result': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) # # FLAVORS # + @bottle.route(url_base + '//flavors', method='GET') def http_get_flavors(tenant_id): my = config_dic['http_threads'][ threading.current_thread().name ] @@ -1600,14 +1619,14 @@ def http_post_server_id(tenant_id): r,c = config_dic['host_threads'][ server['host_id'] ].insert_task( 'restore-iface',*port ) if r < 0: print ' http_post_servers ERROR RESTORE IFACE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c - #updata nets - for net in nets: - r,c = config_dic['of_thread'].insert_task("update-net", net) - if r < 0: - print ':http_post_servers ERROR UPDATING NETS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c + # update nets + for net_id in nets: + try: + my.ovim.net_update_ofc_thread(net_id) + except ovim.ovimException as e: + my.logger.error("http_post_servers, Error updating network with id '{}', '{}'".format(net_id, str(e))) - - #look for dhcp ip address + # 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: @@ -1626,12 +1645,13 @@ def http_post_server_id(tenant_id): 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']) + gateway = str(server_net['network']['gateway']) 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']) http_controller = config_dic['http_threads'][threading.current_thread().name] - http_controller.ovim.launch_dhcp_server(vlan, dhcp_firt_ip, dhcp_last_ip, dhcp_cidr) + http_controller.ovim.launch_dhcp_server(vlan, dhcp_firt_ip, dhcp_last_ip, dhcp_cidr, gateway) #Start server server['uuid'] = new_instance @@ -1772,7 +1792,8 @@ def http_server_action(server_id, tenant_id, action): return http_get_image_id(tenant_id, image_uuid) #Update DB only for CREATING or DELETING status - data={'result' : 'in process'} + data={'result' : 'deleting in process'} + warn_text="" if new_status != None and new_status == 'DELETING': nets=[] ports_to_free=[] @@ -1784,14 +1805,16 @@ def http_server_action(server_id, tenant_id, action): for port in ports_to_free: r1,c1 = config_dic['host_threads'][ server['host_id'] ].insert_task( 'restore-iface',*port ) if r1 < 0: - print ' http_post_server_action error at server deletion ERROR resore-iface !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c1 - data={'result' : 'deleting in process, but ifaces cannot be restored!!!!!'} - for net in nets: - r1,c1 = config_dic['of_thread'].insert_task("update-net", net) - if r1 < 0: - print ' http_post_server_action error at server deletion ERROR UPDATING NETS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c1 - data={'result' : 'deleting in process, but openflow rules cannot be deleted!!!!!'} - #look for dhcp ip address + my.logger.error("http_post_server_action server deletion ERROR at resore-iface!!!! " + c1) + warn_text += "; Error iface '{}' cannot be restored '{}'".format(str(port), str(e)) + for net_id in nets: + try: + my.ovim.net_update_ofc_thread(net_id) + except ovim.ovimException as e: + my.logger.error("http_server_action, Error updating network with id '{}', '{}'".format(net_id, str(e))) + warn_text += "; Error openflow rules of network '{}' cannot be restore '{}'".format(net_id, str (e)) + + # look for dhcp ip address if r2 >0 and config_dic.get("dhcp_server"): for iface in c2: if iface["net_id"] in config_dic["dhcp_nets"]: @@ -1808,7 +1831,7 @@ def http_server_action(server_id, tenant_id, action): 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) + return format_out(data + warn_text) @@ -1847,438 +1870,371 @@ def http_post_server_action(tenant_id, server_id): @bottle.route(url_base + '/networks', method='GET') def http_get_networks(): - my = config_dic['http_threads'][ threading.current_thread().name ] - #obtain data - select_,where_,limit_ = filter_query_string(bottle.request.query, http2db_network, - ('id','name','tenant_id','type', - 'shared','provider:vlan','status','last_error','admin_state_up','provider:physical') ) - #TODO temporally remove tenant_id - if "tenant_id" in where_: - del where_["tenant_id"] - result, content = my.db.get_table(SELECT=select_, FROM='nets', WHERE=where_, LIMIT=limit_) - if result < 0: - print "http_get_networks error %d %s" % (result, content) - bottle.abort(-result, content) - else: - convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp')) - delete_nulls(content) - change_keys_http2db(content, http2db_network, reverse=True) - data={'networks' : content} + """ + Get all networks available + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + # obtain data + select_, where_, limit_ = filter_query_string(bottle.request.query, http2db_network, + ('id', 'name', 'tenant_id', 'type', + 'shared', 'provider:vlan', 'status', 'last_error', + 'admin_state_up', 'provider:physical')) + if "tenant_id" in where_: + del where_["tenant_id"] + + content = my.ovim.get_networks(select_, where_, limit_) + + delete_nulls(content) + change_keys_http2db(content, http2db_network, reverse=True) + data = {'networks': content} return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + @bottle.route(url_base + '/networks/', method='GET') def http_get_network_id(network_id): - data = get_network_id(network_id) - return format_out(data) + """ + Get a network data by id + :param network_id: + :return: + """ + data = get_network_id(network_id) + return format_out(data) + def get_network_id(network_id): + """ + Get network from DB by id + :param network_id: network Id + :return: + """ 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) - if result < 0: - print "http_get_networks_id error %d %s" % (result, content) - bottle.abort(-result, content) - elif result==0: - 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', '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',), - WHERE={'net_id': network_id}, LIMIT=100) - if len(ports) > 0: - content[0]['ports'] = ports - delete_nulls(content[0]) - data={'network' : content[0]} + try: + # obtain data + where_ = bottle.request.query + content = my.ovim.show_network(network_id, where_) + + change_keys_http2db(content, http2db_network, reverse=True) + delete_nulls(content) + data = {'network': content} return data + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + @bottle.route(url_base + '/networks', method='POST') def http_post_networks(): - '''insert a network into the database.''' - my = config_dic['http_threads'][ threading.current_thread().name ] - #parse input data - http_content = format_in( network_new_schema ) - r = remove_extra_items(http_content, network_new_schema) - if r is not None: print "http_post_networks: Warning: remove extra items ", r - change_keys_http2db(http_content['network'], http2db_network) - network=http_content['network'] - #check valid tenant_id - tenant_id= network.get('tenant_id') - if tenant_id!=None: - result, _ = my.db.get_table(FROM='tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id,"enabled":True}) - if result<=0: - bottle.abort(HTTP_Not_Found, 'tenant %s not found or not enabled' % tenant_id) - return - bridge_net = None - #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") - name = network["name"] - - #check if network name ends with : and network exist in order to make and automated bindning - vlan_index =name.rfind(":") - if net_bind_net==None and net_bind_type==None and vlan_index > 1: - try: - vlan_tag = int(name[vlan_index+1:]) - if vlan_tag >0 and vlan_tag < 4096: - net_bind_net = name[:vlan_index] - net_bind_type = "vlan:" + name[vlan_index+1:] - except: - pass - - if net_bind_net != None: - #look for a valid net - if check_valid_uuid(net_bind_net): - net_bind_key = "uuid" - else: - net_bind_key = "name" - result, content = my.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net} ) - if result<0: - bottle.abort(HTTP_Internal_Server_Error, 'getting nets from db ' + content) - return - elif result==0: - bottle.abort(HTTP_Bad_Request, "bind_net %s '%s'not found" % (net_bind_key, net_bind_net) ) - return - elif result>1: - bottle.abort(HTTP_Bad_Request, "more than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net) ) - return - network["bind_net"] = content[0]["uuid"] - if net_bind_type != None: - if net_bind_type[0:5] != "vlan:": - bottle.abort(HTTP_Bad_Request, "bad format for 'bind_type', must be 'vlan:'") - return - if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:])<=0 : - bottle.abort(HTTP_Bad_Request, "bad format for 'bind_type', must be 'vlan:' with a tag between 1 and 4095") - return - network["bind_type"] = net_bind_type - - if net_provider!=None: - if net_provider[:9]=="openflow:": - if net_type!=None: - if net_type!="ptp" and net_type!="data": - bottle.abort(HTTP_Bad_Request, "Only 'ptp' or 'data' net types can be bound to 'openflow'") - else: - net_type='data' - else: - if net_type!=None: - if net_type!="bridge_man" and net_type!="bridge_data": - bottle.abort(HTTP_Bad_Request, "Only 'bridge_man' or 'bridge_data' net types can be bound to 'bridge', 'macvtap' or 'default") - else: - net_type='bridge_man' - - if net_type==None: - net_type='bridge_man' - - if net_provider != None: - if net_provider[:7]=='bridge:': - #check it is one of the pre-provisioned bridges - bridge_net_name = net_provider[7:] - for brnet in config_dic['bridge_nets']: - if brnet[0]==bridge_net_name: # free - if brnet[3] != None: - bottle.abort(HTTP_Conflict, "invalid 'provider:physical', bridge '%s' is already used" % bridge_net_name) - return - bridge_net=brnet - net_vlan = brnet[1] - break -# 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 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 - if bridge_net != None: - if net_type=='bridge_man': #look for the smaller speed - if brnet[2] < bridge_net[2]: bridge_net = brnet - else: #look for the larger speed - if brnet[2] > bridge_net[2]: bridge_net = brnet - else: - bridge_net = brnet - net_vlan = brnet[1] - if bridge_net==None: - bottle.abort(HTTP_Bad_Request, "Max limits of bridge networks reached. Future versions of VIM will overcome this limit") - return - else: - print "using net", bridge_net - net_provider = "bridge:"+bridge_net[0] - net_vlan = bridge_net[1] - 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 - dhcp_integrity = True - if 'enable_dhcp' in network and network['enable_dhcp']: - dhcp_integrity = check_dhcp_data_integrity(network) - - result, content = my.db.new_row('nets', network, True, True) - - if result >= 0 and dhcp_integrity: - if bridge_net!=None: - bridge_net[3] = content - 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 - elif bridge_net != None and bridge_net[0] in config_dic["dhcp_server"].get("bridge_ifaces", () ): - config_dic["dhcp_nets"].append(content) - print "dhcp_server: add new net", content - return http_get_network_id(content) - else: - print "http_post_networks error %d %s" % (result, content) - bottle.abort(-result, content) - 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 + Insert a network into the database. :return: """ - control_iface = [] - - if "cidr" in network: - cidr = network["cidr"] - ip_tools = IPNetwork(cidr) - cidr_len = ip_tools.prefixlen - if cidr_len > 29: - return False - - 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]) - - return True - else: - return False + my = config_dic['http_threads'][threading.current_thread().name] + + try: + # parse input data + http_content = format_in(network_new_schema ) + r = remove_extra_items(http_content, network_new_schema) + if r is not None: + print "http_post_networks: Warning: remove extra items ", r + change_keys_http2db(http_content['network'], http2db_network) + network = http_content['network'] + content = my.ovim.new_network(network) + return format_out(get_network_id(content)) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) @bottle.route(url_base + '/networks/', method='PUT') def http_put_network_id(network_id): - '''update a network_id into the database.''' - my = config_dic['http_threads'][ threading.current_thread().name ] - #parse input data - http_content = format_in( network_update_schema ) - r = remove_extra_items(http_content, network_update_schema) - change_keys_http2db(http_content['network'], http2db_network) - network=http_content['network'] - - #Look for the previous data - where_ = {'uuid': network_id} - result, network_old = my.db.get_table(FROM='nets', WHERE=where_) - if result < 0: - print "http_put_network_id error %d %s" % (result, network_old) - bottle.abort(-result, network_old) - return - elif result==0: - print "http_put_network_id network '%s' not found" % network_id - bottle.abort(HTTP_Not_Found, 'network %s not found' % network_id) - return - #get ports - nbports, content = my.db.get_table(FROM='ports', SELECT=('uuid as port_id',), - WHERE={'net_id': network_id}, LIMIT=100) - if result < 0: - print "http_put_network_id error %d %s" % (result, network_old) - bottle.abort(-result, content) - return - if nbports>0: - if 'type' in network and network['type'] != network_old[0]['type']: - bottle.abort(HTTP_Method_Not_Allowed, "Can not change type of network while having ports attached") - if 'vlan' in network and network['vlan'] != network_old[0]['vlan']: - bottle.abort(HTTP_Method_Not_Allowed, "Can not change vlan of network while having ports attached") - - #check valid params - net_provider = network.get('provider', network_old[0]['provider']) - net_type = network.get('type', network_old[0]['type']) - net_bind_net = network.get("bind_net") - net_bind_type= network.get("bind_type") - if net_bind_net != None: - #look for a valid net - if check_valid_uuid(net_bind_net): - net_bind_key = "uuid" - else: - net_bind_key = "name" - result, content = my.db.get_table(FROM='nets', WHERE={net_bind_key: net_bind_net} ) - if result<0: - bottle.abort(HTTP_Internal_Server_Error, 'getting nets from db ' + content) - return - elif result==0: - bottle.abort(HTTP_Bad_Request, "bind_net %s '%s'not found" % (net_bind_key, net_bind_net) ) - return - elif result>1: - bottle.abort(HTTP_Bad_Request, "more than one bind_net %s '%s' found, use uuid" % (net_bind_key, net_bind_net) ) - return - network["bind_net"] = content[0]["uuid"] - if net_bind_type != None: - if net_bind_type[0:5] != "vlan:": - bottle.abort(HTTP_Bad_Request, "bad format for 'bind_type', must be 'vlan:'") - return - if int(net_bind_type[5:]) > 4095 or int(net_bind_type[5:])<=0 : - bottle.abort(HTTP_Bad_Request, "bad format for 'bind_type', must be 'vlan:' with a tag between 1 and 4095") - return - if net_provider!=None: - if net_provider[:9]=="openflow:": - if net_type!="ptp" and net_type!="data": - bottle.abort(HTTP_Bad_Request, "Only 'ptp' or 'data' net types can be bound to 'openflow'") - else: - if net_type!="bridge_man" and net_type!="bridge_data": - bottle.abort(HTTP_Bad_Request, "Only 'bridge_man' or 'bridge_data' net types can be bound to 'bridge', 'macvtap' or 'default") + """ + Update a network_id into DB. + :param network_id: network id + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + # parse input data + http_content = format_in(network_update_schema) + change_keys_http2db(http_content['network'], http2db_network) + network = http_content['network'] + return format_out(my.ovim.edit_network(network_id, network)) + + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) - #insert in data base - result, content = my.db.update_rows('nets', network, WHERE={'uuid': network_id}, log=True ) - if result >= 0: - if result>0: # and nbports>0 and 'admin_state_up' in network and network['admin_state_up'] != network_old[0]['admin_state_up']: - r,c = config_dic['of_thread'].insert_task("update-net", network_id) - if r < 0: - print "http_put_network_id error while launching openflow rules" - bottle.abort(HTTP_Internal_Server_Error, c) - if config_dic.get("dhcp_server"): - if network_id in config_dic["dhcp_nets"]: - config_dic["dhcp_nets"].remove(network_id) - print "dhcp_server: delete net", network_id - if network.get("name", network_old["name"]) in config_dic["dhcp_server"].get("nets", () ): - config_dic["dhcp_nets"].append(network_id) - print "dhcp_server: add new net", network_id - else: - net_bind = network.get("bind", network_old["bind"] ) - if net_bind and net_bind[:7]=="bridge:" and net_bind[7:] in config_dic["dhcp_server"].get("bridge_ifaces", () ): - config_dic["dhcp_nets"].append(network_id) - print "dhcp_server: add new net", network_id - return http_get_network_id(network_id) - else: - bottle.abort(-result, content) - return - @bottle.route(url_base + '/networks/', method='DELETE') def http_delete_network_id(network_id): - '''delete a network_id from the database.''' - my = config_dic['http_threads'][ threading.current_thread().name ] + """ + Delete a network_id from the database. + :param network_id: Network id + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] - #delete from the data base - result, content = my.db.delete_row('nets', network_id ) - - if result == 0: - bottle.abort(HTTP_Not_Found, content) - elif result >0: - for brnet in config_dic['bridge_nets']: - if brnet[3]==network_id: - brnet[3]=None - break - if config_dic.get("dhcp_server") and network_id in config_dic["dhcp_nets"]: - config_dic["dhcp_nets"].remove(network_id) - print "dhcp_server: delete net", network_id - data={'result' : content} + try: + # delete from the data base + content = my.ovim.delete_network(network_id) + data = {'result': content} return format_out(data) - else: - print "http_delete_network_id error",result, content - bottle.abort(-result, content) - return + + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + # # OPENFLOW # + + +@bottle.route(url_base + '/openflow/controller', method='GET') +def http_get_openflow_controller(): + """ + Retrieve a openflow controllers list from DB. + :return: + """ + # TODO check if show a proper list + my = config_dic['http_threads'][threading.current_thread().name] + + try: + select_, where_, limit_ = filter_query_string(bottle.request.query, http2db_ofc, + ('id', 'name', 'dpid', 'ip', 'port', 'type', + 'version', 'user', 'password')) + + content = my.ovim.get_of_controllers(select_, where_) + delete_nulls(content) + change_keys_http2db(content, http2db_ofc, reverse=True) + data = {'ofcs': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/controller/', method='GET') +def http_get_openflow_controller_id(uuid): + """ + Get an openflow controller by dpid from DB.get_of_controllers + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + + content = my.ovim.show_of_controller(uuid) + delete_nulls(content) + change_keys_http2db(content, http2db_ofc, reverse=True) + data = {'ofc': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/controller/', method='POST') +def http_post_openflow_controller(): + """ + Create a new openflow controller into DB + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + http_content = format_in(openflow_controller_schema) + of_c = http_content['ofc'] + uuid = my.ovim.new_of_controller(of_c) + content = my.ovim.show_of_controller(uuid) + delete_nulls(content) + change_keys_http2db(content, http2db_ofc, reverse=True) + data = {'ofc': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/controller/', method='PUT') +def http_put_openflow_controller_by_id(of_controller_id): + """ + Create an openflow controller into DB + :param of_controller_id: openflow controller dpid + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + http_content = format_in(openflow_controller_schema) + of_c = http_content['ofc'] + + content = my.ovim.edit_of_controller(of_controller_id, of_c) + delete_nulls(content) + change_keys_http2db(content, http2db_ofc, reverse=True) + data = {'ofc': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/controller/', method='DELETE') +def http_delete_openflow_controller(of_controller_id): + """ + Delete an openflow controller from DB. + :param of_controller_id: openflow controller dpid + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + content = my.ovim.delete_of_controller(of_controller_id) + data = {'result': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + @bottle.route(url_base + '/networks//openflow', method='GET') def http_get_openflow_id(network_id): - '''To obtain the list of openflow rules of a network - ''' - my = config_dic['http_threads'][ threading.current_thread().name ] - #ignore input data - if network_id=='all': - where_={} - else: - where_={"net_id": network_id} - result, content = my.db.get_table(SELECT=("name","net_id","priority","vlan_id","ingress_port","src_mac","dst_mac","actions"), - WHERE=where_, FROM='of_flows') - if result < 0: - bottle.abort(-result, content) - return - data={'openflow-rules' : content} + """ + To obtain the list of openflow rules of a network + :param network_id: network id + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + # ignore input data + if network_id == 'all': + network_id = None + try: + content = my.ovim.get_openflow_rules(network_id) + data = {'openflow-rules': content} + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + return format_out(data) + @bottle.route(url_base + '/networks//openflow', method='PUT') def http_put_openflow_id(network_id): - '''To make actions over the net. The action is to reinstall the openflow rules + """ + To make actions over the net. The action is to reinstall the openflow rules network_id can be 'all' - ''' - my = config_dic['http_threads'][ threading.current_thread().name ] + :param network_id: network id + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + if not my.admin: bottle.abort(HTTP_Unauthorized, "Needed admin privileges") - return - #ignore input data - if network_id=='all': - where_={} - else: - where_={"uuid": network_id} - result, content = my.db.get_table(SELECT=("uuid","type"), WHERE=where_, FROM='nets') - if result < 0: - bottle.abort(-result, content) - return - - for net in content: - if net["type"]!="ptp" and net["type"]!="data": - result-=1 - continue - r,c = config_dic['of_thread'].insert_task("update-net", net['uuid']) - if r < 0: - print "http_put_openflow_id error while launching openflow rules" - bottle.abort(HTTP_Internal_Server_Error, c) - data={'result' : str(result)+" nets updates"} + + if network_id == 'all': + network_id = None + + try: + result = my.ovim.edit_openflow_rules(network_id) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + data = {'result': str(result) + " nets updates"} return format_out(data) -@bottle.route(url_base + '/networks/openflow/clear', method='DELETE') +@bottle.route(url_base + '/networks/clear/openflow/', method='DELETE') @bottle.route(url_base + '/networks/clear/openflow', method='DELETE') -def http_clear_openflow_rules(): - '''To make actions over the net. The action is to delete ALL openflow rules - ''' - my = config_dic['http_threads'][ threading.current_thread().name ] +def http_clear_openflow_rules(ofc_id=None): + """ + To make actions over the net. The action is to delete ALL openflow rules + :return: + """ + my = config_dic['http_threads'][ threading.current_thread().name] + if not my.admin: bottle.abort(HTTP_Unauthorized, "Needed admin privileges") - return - #ignore input data - r,c = config_dic['of_thread'].insert_task("clear-all") - if r < 0: - print "http_delete_openflow_id error while launching openflow rules" - bottle.abort(HTTP_Internal_Server_Error, c) - return + try: + my.ovim.delete_openflow_rules(ofc_id) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) - data={'result' : " Clearing openflow rules in process"} + data = {'result': " Clearing openflow rules in process"} return format_out(data) +@bottle.route(url_base + '/networks/openflow/ports/', method='GET') @bottle.route(url_base + '/networks/openflow/ports', method='GET') -def http_get_openflow_ports(): - '''Obtain switch ports names of openflow controller - ''' - data={'ports' : config_dic['of_thread'].OF_connector.pp2ofi} - return format_out(data) +def http_get_openflow_ports(ofc_id=None): + """ + Obtain switch ports names of openflow controller + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + try: + ports = my.ovim.get_openflow_ports(ofc_id) + data = {'ports': ports} + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + return format_out(data) # # PORTS # + @bottle.route(url_base + '/ports', method='GET') def http_get_ports(): #obtain data @@ -2397,3 +2353,78 @@ def http_delete_port_id(port_id): bottle.abort(HTTP_Bad_Request, str(e)) +@bottle.route(url_base + '/openflow/mapping', method='POST') +def http_of_port_mapping(): + """ + Create new compute port mapping entry + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + http_content = format_in(of_port_map_new_schema) + r = remove_extra_items(http_content, of_port_map_new_schema) + if r is not None: + my.logger.error("http_of_port_mapping: Warning: remove extra items " + str(r), exc_info=True) + + # insert in data base + port_mapping = my.ovim.set_of_port_mapping(http_content['of_port_mapings']) + change_keys_http2db(port_mapping, http2db_id, reverse=True) + delete_nulls(port_mapping) + data = {'of_port_mappings': port_mapping} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/mapping', method='GET') +def get_of_port_mapping(): + """ + Get compute port mapping + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + select_, where_, limit_ = filter_query_string(bottle.request.query, http2db_id, + ('id', 'ofc_id', 'region', 'compute_node', 'pci', + 'switch_dpid', 'switch_port', 'switch_mac')) + # insert in data base + port_mapping = my.ovim.get_of_port_mappings(select_, where_) + change_keys_http2db(port_mapping, http2db_id, reverse=True) + delete_nulls(port_mapping) + data = {'of_port_mappings': port_mapping} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/mapping/', method='DELETE') +def delete_of_port_mapping(region): + """ + Insert a tenant into the database. + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + # insert in data base + db_filter = {'region': region} + result = my.ovim.clear_of_port_mapping(db_filter) + data = {'result': result} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) +