Add openflow-port-mapping CLI command
[osm/openvim.git] / httpserver.py
index c8d093f..edf1e8d 100644 (file)
@@ -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/<tenant_id>', 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/<tenant_id>', 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/<tenant_id>', 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 + '/<tenant_id>/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/<network_id>', 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 :<vlan_tag> 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:<tag>'")
-            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:<tag>' 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/<network_id>', 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:<tag>'")
-            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:<tag>' 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/<network_id>', 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/<uuid>', 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/<of_controller_id>', 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/<of_controller_id>', 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/<network_id>/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/<network_id>/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/<ofc_id>', 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/<ofc_id>', 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/<region>', 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))
+