Merge branch 'v1.1' 80/1080/2
authortierno <alfonso.tiernosepulveda@telefonica.com>
Wed, 8 Feb 2017 13:21:28 +0000 (14:21 +0100)
committertierno <alfonso.tiernosepulveda@telefonica.com>
Wed, 8 Feb 2017 14:58:37 +0000 (15:58 +0100)
Change-Id: I0c27f01914959623bf25905786af9e7dabc141b6
Signed-off-by: tierno <alfonso.tiernosepulveda@telefonica.com>
1  2 
database_utils/migrate_vim_db.sh
host_thread.py
httpserver.py
openvimd.cfg
openvimd.py
vim_db.py

@@@ -175,8 -175,8 +175,9 @@@ DATABASE_TARGET_VER_NUM=
  [ $OPENVIM_VER_NUM -ge 4001 ] && DATABASE_TARGET_VER_NUM=5   #0.4.1   =>  5
  [ $OPENVIM_VER_NUM -ge 4002 ] && DATABASE_TARGET_VER_NUM=6   #0.4.2   =>  6
  [ $OPENVIM_VER_NUM -ge 4005 ] && DATABASE_TARGET_VER_NUM=7   #0.4.5   =>  7
 -[ $OPENVIM_VER_NUM -ge 4010 ] && DATABASE_TARGET_VER_NUM=8   #0.4.10   =>  8
 +[ $OPENVIM_VER_NUM -ge 4010 ] && DATABASE_TARGET_VER_NUM=8   #0.4.10  =>  8
- [ $OPENVIM_VER_NUM -ge 5002 ] && DATABASE_TARGET_VER_NUM=9   #0.5.2   =>  9
+ [ $OPENVIM_VER_NUM -ge 5001 ] && DATABASE_TARGET_VER_NUM=9   #0.5.1   =>  9
++[ $OPENVIM_VER_NUM -ge 5002 ] && DATABASE_TARGET_VER_NUM=10  #0.5.2   => 10
  #TODO ... put next versions here
  
  
@@@ -455,16 -455,19 +456,31 @@@ function downgrade_from_8()
  
  function upgrade_to_9(){
      echo "    upgrade database from version 0.8 to version 0.9"
-     echo "     change types at 'ports'"
-     echo "ALTER TABLE ports CHANGE COLUMN type type ENUM('instance:bridge','instance:data','external','instance:ovs','controller:ovs') NOT NULL DEFAULT 'instance:bridge' AFTER status;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
-     echo "INSERT INTO schema_version (version_int, version, openvim_ver, comments, date) VALUES (9, '0.9', '0.5.2', 'add column checksum to images', '2016-09-30');"| $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+     echo "     change length of columns 'path' and 'name' to 255 in table 'images', and change length of column 'name' to 255 in table 'flavors'"
+     echo "ALTER TABLE images CHANGE COLUMN path path VARCHAR(255) NOT NULL AFTER uuid, CHANGE COLUMN name name VARCHAR(255) NOT NULL AFTER path;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+     echo "ALTER TABLE flavors CHANGE COLUMN name name VARCHAR(255) NOT NULL AFTER uuid;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+     echo "INSERT INTO schema_version (version_int, version, openvim_ver, comments, date) VALUES (9, '0.9', '0.5.1', 'increase length of columns path and name to 255 in table images, and change length of column name to 255 in table flavors', '2017-01-10');"| $DBCMD || ! echo "ERROR. Aborted!" || exit -1
  }
  function downgrade_from_9(){
      echo "    downgrade database from version 0.9 to version 0.8"
-     echo "DELETE FROM schema_version WHERE version_int = '9';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+     echo "     change length of columns 'path' and 'name' to 100 and 64 in table 'images'"
+     echo "ALTER TABLE images CHANGE COLUMN path path VARCHAR(100) NOT NULL AFTER uuid, CHANGE COLUMN name name VARCHAR(64) NOT NULL AFTER path;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+     echo "ALTER TABLE flavors CHANGE COLUMN name name VARCHAR(64) NOT NULL AFTER uuid;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+     echo "DELETE FROM schema_version WHERE version_int = '9';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ }
++function upgrade_to_10(){
++    echo "    upgrade database from version 0.9 to version 0.10"
++    echo "     change types at 'ports'"
++    echo "ALTER TABLE ports CHANGE COLUMN type type ENUM('instance:bridge','instance:data','external','instance:ovs','controller:ovs') NOT NULL DEFAULT 'instance:bridge' AFTER status;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
++    echo "INSERT INTO schema_version (version_int, version, openvim_ver, comments, date) VALUES (10, '0.10', '0.5.2', 'change ports type, adding instance:ovs', '2017-02-01');"| $DBCMD || ! echo "ERROR. Aborted!" || exit -1
++}
++function downgrade_from_10(){
++    echo "    downgrade database from version 0.10 to version 0.9"
 +    echo "     change back types at 'ports'"
 +    echo "ALTER TABLE ports CHANGE COLUMN type type ENUM('instance:bridge','instance:data','external') NOT NULL DEFAULT 'instance:bridge' AFTER status;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
++    echo "DELETE FROM schema_version WHERE version_int = '10';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
 +}
  #TODO ... put funtions here
  
  
diff --combined host_thread.py
@@@ -25,8 -25,9 +25,8 @@@
  This is thread that interact with the host and the libvirt to manage VM
  One thread will be launched per host 
  '''
 -__author__="Pablo Montes, Alfonso Tierno"
 -__date__ ="$10-jul-2014 12:07:15$"
 -
 +__author__ = "Pablo Montes, Alfonso Tierno, Leonardo Mirabal"
 +__date__ = "$10-jul-2014 12:07:15$"
  
  import json
  import yaml
@@@ -39,25 -40,17 +39,23 @@@ from jsonschema import validate as js_v
  import imp
  from vim_schema import localinfo_schema, hostinfo_schema
  import random
 -#from logging import Logger
 -#import auxiliary_functions as af
 +import os
  
+ #TODO: insert a logging system
  
 +# from logging import Logger
 +# import auxiliary_functions as af
 +
 +# TODO: insert a logging system
 +
  
- # global lvirt_module
- # lvirt_module=None  #libvirt module is charged only if not in test mode
  class host_thread(threading.Thread):
 -    lvirt_module = None  # libvirt module is charged only if not in test mode
 -    def __init__(self, name, host, user, db, db_lock, test, image_path, host_id, version, develop_mode, develop_bridge_iface):
 +    lvirt_module = None
 +
 +    def __init__(self, name, host, user, db, db_lock, test, image_path, host_id, version, develop_mode,
 +                 develop_bridge_iface):
          '''Init a thread.
 -        Arguments: 
 +        Arguments:
              'id' number of thead
              'name' name of thread
              'host','user':  host ip or name to manage and user
@@@ -70,8 -63,7 +68,8 @@@
          self.db = db
          self.db_lock = db_lock
          self.test = test
 -        if not test and host_thread.lvirt_module == None:
 +
 +        if not test and not host_thread.lvirt_module:
              try:
                  module_info = imp.find_module("libvirt")
                  host_thread.lvirt_module = imp.load_module("libvirt", *module_info)
@@@ -96,8 -88,7 +94,8 @@@
          
          self.queueLock = threading.Lock()
          self.taskQueue = Queue.Queue(2000)
 -        
 +        self.ssh_conn = None
 +
      def ssh_connect(self):
          try:
              #Connect SSH
                  elif task[0] == 'restore-iface':
                      print self.name, ": processing task restore-iface %s mac=%s" % (task[1], task[2])
                      self.restore_iface(task[1], task[2])
 +                elif task[0] == 'new-ovsbridge':
 +                    print self.name, ": Creating compute OVS bridge"
 +                    self.create_ovs_bridge()
 +                    break
 +                elif task[0] == 'new-vxlan':
 +                    print self.name, ": Creating vxlan tunnel=" + task[1] + ", remote ip=" + task[2]
 +                    self.create_ovs_vxlan_tunnel(task[1], task[2])
 +                    break
 +                elif task[0] == 'del-ovsbridge':
 +                    print self.name, ": Deleting OVS bridge"
 +                    self.delete_ovs_bridge()
 +                    break
 +                elif task[0] == 'del-vxlan':
 +                    print self.name, ": Deleting vxlan " + task[1] + " tunnel"
 +                    self.delete_ovs_vxlan_tunnel(task[1])
 +                    break
 +                elif task[0] == 'create-ovs-bridge-port':
 +                    print self.name, ": Adding port ovim-" + task[1] + " to OVS bridge"
 +                    self.create_ovs_bridge_port(task[1])
 +                elif task[0] == 'del-ovs-port':
 +                    self.delete_bridge_port_attached_to_ovs(task[1], task[2])
                  else:
                      print self.name, ": unknown task", task
                  
                          self.tab() + "<alias name='net" + str(net_nb)+ "'/>"
                  elif model==None:
                      model = "virtio"
 +            elif content[0]['provider'][0:3] == "OVS":
 +                vlan = content[0]['provider'].replace('OVS:', '')
 +                text += self.tab() + "<interface type='bridge'>" + \
 +                        self.inc_tab() + "<source bridge='ovim-" + vlan + "'/>"
              else:
                  return -1, 'Unknown Bridge net provider ' + content[0]['provider']
              if model!=None:
          """Decrement and return indentation according to xml_level"""
          self.xml_level -= 1
          return self.tab()
 -    
 +
 +    def create_ovs_bridge(self):
 +        """
 +        Create a bridge in compute OVS to allocate VMs
 +        :return: True if success
 +        """
 +        if self.test:
 +            return
 +        command = 'sudo ovs-vsctl --may-exist add-br br-int -- set Bridge br-int stp_enable=true'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def delete_port_to_ovs_bridge(self, vlan, net_uuid):
 +        """
 +        Delete linux bridge port attched to a OVS bridge, if port is not free the port is not removed
 +        :param vlan: vlan port id
 +        :param net_uuid: network id
 +        :return:
 +        """
 +
 +        if self.test:
 +            return
 +
 +        port_name = 'ovim-' + vlan
 +        command = 'sudo ovs-vsctl del-port br-int ' + port_name
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def delete_dhcp_server(self, vlan, net_uuid, dhcp_path):
 +        """
 +        Delete dhcp server process lining in namespace
 +        :param vlan: segmentation id
 +        :param net_uuid: network uuid
 +        :param dhcp_path: conf fiel path that live in namespace side
 +        :return:
 +        """
 +        if self.test:
 +            return
 +        if not self.is_dhcp_port_free(vlan, net_uuid):
 +            return True
 +
 +        net_namespace = 'ovim-' + vlan
 +        dhcp_path = os.path.join(dhcp_path, net_namespace)
 +        pid_file = os.path.join(dhcp_path, 'dnsmasq.pid')
 +
 +        command = 'sudo ip netns exec ' + net_namespace + ' cat ' + pid_file
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo ip netns exec ' + net_namespace + ' kill -9 ' + content
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        # if len(content) == 0:
 +        #     return True
 +        # else:
 +        #     return False
 +
 +    def is_dhcp_port_free(self, host_id, net_uuid):
 +        """
 +        Check if any port attached to the a net in a vxlan mesh across computes nodes
 +        :param host_id: host id
 +        :param net_uuid: network id
 +        :return: True if is not free
 +        """
 +        self.db_lock.acquire()
 +        result, content = self.db.get_table(
 +            FROM='ports',
 +            WHERE={'p.type': 'instance:ovs', 'p.net_id': net_uuid}
 +        )
 +        self.db_lock.release()
 +
 +        if len(content) > 0:
 +            return False
 +        else:
 +            return True
 +
 +    def is_port_free(self, host_id, net_uuid):
 +        """
 +        Check if there not ovs ports of a network in a compute host.
 +        :param host_id:  host id
 +        :param net_uuid: network id
 +        :return: True if is not free
 +        """
 +
 +        self.db_lock.acquire()
 +        result, content = self.db.get_table(
 +            FROM='ports as p join instances as i on p.instance_id=i.uuid',
 +            WHERE={"i.host_id": self.host_id, 'p.type': 'instance:ovs', 'p.net_id': net_uuid}
 +        )
 +        self.db_lock.release()
 +
 +        if len(content) > 0:
 +            return False
 +        else:
 +            return True
 +
 +    def add_port_to_ovs_bridge(self, vlan):
 +        """
 +        Add a bridge linux as a port to a OVS bridge and set a vlan for an specific linux bridge
 +        :param vlan: vlan port id
 +        :return: True if success
 +        """
 +
 +        if self.test:
 +            return
 +
 +        port_name = 'ovim-' + vlan
 +        command = 'sudo ovs-vsctl add-port br-int ' + port_name + ' tag=' + vlan
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def delete_dhcp_port(self, vlan, net_uuid):
 +        """
 +        Delete from an existing OVS bridge a linux bridge port attached and the linux bridge itself.
 +        :param vlan: segmentation id
 +        :param net_uuid: network id
 +        :return: True if success
 +        """
 +
 +        if self.test:
 +            return
 +
 +        if not self.is_dhcp_port_free(vlan, net_uuid):
 +            return True
 +        self.delete_dhcp_interfaces(vlan)
 +        return True
 +
 +    def delete_bridge_port_attached_to_ovs(self, vlan, net_uuid):
 +        """
 +        Delete from an existing OVS bridge a linux bridge port attached and the linux bridge itself.
 +        :param vlan:
 +        :param net_uuid:
 +        :return: True if success
 +        """
 +        if self.test:
 +            return
 +
 +        if not self.is_port_free(vlan, net_uuid):
 +            return True
 +        self.delete_port_to_ovs_bridge(vlan, net_uuid)
 +        self.delete_linux_bridge(vlan)
 +        return True
 +
 +    def delete_linux_bridge(self, vlan):
 +        """
 +        Delete a linux bridge in a scpecific compute.
 +        :param vlan: vlan port id
 +        :return: True if success
 +        """
 +
 +        if self.test:
 +            return
 +
 +        port_name = 'ovim-' + vlan
 +        command = 'sudo ip link set dev veth0-' + vlan + ' down'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +        #
 +        # if len(content) != 0:
 +        #     return False
 +
 +        command = 'sudo ifconfig ' + port_name + ' down &&  sudo brctl delbr ' + port_name
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def create_ovs_bridge_port(self, vlan):
 +        """
 +        Generate a linux bridge and attache the port to a OVS bridge
 +        :param vlan: vlan port id
 +        :return:
 +        """
 +        if self.test:
 +            return
 +        self.create_linux_bridge(vlan)
 +        self.add_port_to_ovs_bridge(vlan)
 +
 +    def create_linux_bridge(self, vlan):
 +        """
 +        Create a linux bridge with STP active
 +        :param vlan: netowrk vlan id
 +        :return:
 +        """
 +
 +        if self.test:
 +            return
 +
 +        port_name = 'ovim-' + vlan
 +        command = 'sudo brctl show | grep ' + port_name
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        # if exist nothing to create
 +        # if len(content) == 0:
 +        #     return False
 +
 +        command = 'sudo brctl addbr ' + port_name
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        # if len(content) == 0:
 +        #     return True
 +        # else:
 +        #     return False
 +
 +        command = 'sudo brctl stp ' + port_name + ' on'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        # if len(content) == 0:
 +        #     return True
 +        # else:
 +        #     return False
 +        command = 'sudo ip link set dev ' + port_name + ' up'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def set_mac_dhcp_server(self, ip, mac, vlan, netmask, dhcp_path):
 +        """
 +        Write into dhcp conf file a rule to assigned a fixed ip given to an specific MAC address
 +        :param ip: IP address asigned to a VM
 +        :param mac: VM vnic mac to be macthed with the IP received
 +        :param vlan: Segmentation id
 +        :param netmask: netmask value
 +        :param path: dhcp conf file path that live in namespace side
 +        :return: True if success
 +        """
 +
 +        if self.test:
 +            return
 +
 +        net_namespace = 'ovim-' + vlan
 +        dhcp_path = os.path.join(dhcp_path, net_namespace)
 +        dhcp_hostsdir = os.path.join(dhcp_path, net_namespace)
 +
 +        if not ip:
 +            return False
 +
 +        ip_data = mac.upper() + ',' + ip
 +
 +        command = 'sudo  ip netns exec ' + net_namespace + ' touch ' + dhcp_hostsdir
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo  ip netns exec ' + net_namespace + ' sudo bash -ec "echo ' + ip_data + ' >> ' + dhcp_hostsdir + '"'
 +
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def delete_mac_dhcp_server(self, ip, mac, vlan, dhcp_path):
 +        """
 +        Delete into dhcp conf file the ip  assigned to a specific MAC address
 +
 +        :param ip: IP address asigned to a VM
 +        :param mac:  VM vnic mac to be macthed with the IP received
 +        :param vlan:  Segmentation id
 +        :param dhcp_path: dhcp conf file path that live in namespace side
 +        :return:
 +        """
 +
 +        if self.test:
 +            return
 +
 +        net_namespace = 'ovim-' + vlan
 +        dhcp_path = os.path.join(dhcp_path, net_namespace)
 +        dhcp_hostsdir = os.path.join(dhcp_path, net_namespace)
 +
 +        if not ip:
 +            return False
 +
 +        ip_data = mac.upper() + ',' + ip
 +
 +        command = 'sudo  ip netns exec ' + net_namespace + ' sudo sed -i \'/' + ip_data + '/d\' ' + dhcp_hostsdir
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def launch_dhcp_server(self, vlan, ip_range, netmask, dhcp_path):
 +        """
 +        Generate a linux bridge and attache the port to a OVS bridge
 +        :param self:
 +        :param vlan: Segmentation id
 +        :param ip_range: IP dhcp range
 +        :param netmask: network netmask
 +        :param dhcp_path: dhcp conf file path that live in namespace side
 +        :return: True if success
 +        """
 +
 +        if self.test:
 +            return
 +
 +        interface = 'tap-' + vlan
 +        net_namespace = 'ovim-' + vlan
 +        dhcp_path = os.path.join(dhcp_path, net_namespace)
 +        leases_path = os.path.join(dhcp_path, "dnsmasq.leases")
 +        pid_file = os.path.join(dhcp_path, 'dnsmasq.pid')
 +
 +        dhcp_range = ip_range[0] + ',' + ip_range[1] + ',' + netmask
 +
 +        command = 'sudo ip netns exec ' + net_namespace + ' mkdir -p ' + dhcp_path
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        pid_path = os.path.join(dhcp_path, 'dnsmasq.pid')
 +        command = 'sudo  ip netns exec ' + net_namespace + ' cat ' + pid_path
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +        # check if pid is runing
 +        pid_status_path = content
 +        if content:
 +            command = "ps aux | awk '{print $2 }' | grep " + pid_status_path
 +            print self.name, ': command:', command
 +            (_, stdout, _) = self.ssh_conn.exec_command(command)
 +            content = stdout.read()
 +        if not content:
 +            command = 'sudo  ip netns exec ' + net_namespace + ' /usr/sbin/dnsmasq --strict-order --except-interface=lo ' \
 +              '--interface=' + interface + ' --bind-interfaces --dhcp-hostsdir=' + dhcp_path + \
 +              ' --dhcp-range ' + dhcp_range + ' --pid-file=' + pid_file + ' --dhcp-leasefile=' + leases_path + '  --listen-address ' + ip_range[0]
 +
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.readline()
 +
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def delete_dhcp_interfaces(self, vlan):
 +        """
 +        Create a linux bridge with STP active
 +        :param vlan: netowrk vlan id
 +        :return:
 +        """
 +
 +        if self.test:
 +            return
 +
 +        net_namespace = 'ovim-' + vlan
 +        command = 'sudo ovs-vsctl del-port br-int ovs-tap-' + vlan
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo ip netns exec ' + net_namespace + ' ip link set dev tap-' + vlan + ' down'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo ip link set dev ovs-tap-' + vlan + ' down'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +    def create_dhcp_interfaces(self, vlan, ip, netmask):
 +        """
 +        Create a linux bridge with STP active
 +        :param vlan: segmentation id
 +        :param ip: Ip included in the dhcp range for the tap interface living in namesapce side
 +        :param netmask: dhcp net CIDR
 +        :return: True if success
 +        """
 +
 +        if self.test:
 +            return
 +
 +        net_namespace = 'ovim-' + vlan
 +        namespace_interface = 'tap-' + vlan
 +
 +        command = 'sudo ip netns add ' + net_namespace
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo ip link add tap-' + vlan + ' type veth peer name ovs-tap-' + vlan
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo ovs-vsctl add-port br-int ovs-tap-' + vlan + ' tag=' + vlan
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo ip link set tap-' + vlan + ' netns ' + net_namespace
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo ip netns exec ' + net_namespace + ' ip link set dev tap-' + vlan + ' up'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo ip link set dev ovs-tap-' + vlan + ' up'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        command = 'sudo  ip netns exec ' + net_namespace + ' ' + ' ifconfig  ' + namespace_interface \
 +                  + ' ' + ip + ' netmask ' + netmask
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def create_ovs_vxlan_tunnel(self, vxlan_interface, remote_ip):
 +        """
 +        Create a vlxn tunnel between to computes with an OVS installed. STP is also active at port level
 +        :param vxlan_interface: vlxan inteface name.
 +        :param remote_ip: tunnel endpoint remote compute ip.
 +        :return:
 +        """
 +        if self.test:
 +            return
 +        command = 'sudo ovs-vsctl add-port br-int ' + vxlan_interface + \
 +                  ' -- set Interface ' + vxlan_interface + '  type=vxlan options:remote_ip=' + remote_ip + \
 +                  ' -- set Port ' + vxlan_interface + ' other_config:stp-path-cost=10'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +        print content
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def delete_ovs_vxlan_tunnel(self, vxlan_interface):
 +        """
 +        Delete a vlxan tunnel  port from a OVS brdige.
 +        :param vxlan_interface: vlxan name to be delete it.
 +        :return: True if success.
 +        """
 +        if self.test:
 +            return
 +        command = 'sudo ovs-vsctl del-port br-int ' + vxlan_interface
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +        print content
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
 +    def delete_ovs_bridge(self):
 +        """
 +        Delete a OVS bridge from  a compute.
 +        :return: True if success
 +        """
 +        if self.test:
 +            return
 +        command = 'sudo ovs-vsctl del-br br-int'
 +        print self.name, ': command:', command
 +        (_, stdout, _) = self.ssh_conn.exec_command(command)
 +        content = stdout.read()
 +        if len(content) == 0:
 +            return True
 +        else:
 +            return False
 +
      def get_file_info(self, path):
          command = 'ls -lL --time-style=+%Y-%m-%dT%H:%M:%S ' + path
          print self.name, ': command:', command
                      continue
                  
                  self.db_lock.acquire()
 -                result, content = self.db.get_table(FROM='images', SELECT=('path','metadata'),WHERE={'uuid':dev['image_id']} )
 +                result, content = self.db.get_table(FROM='images', SELECT=('path', 'metadata'),
 +                                                    WHERE={'uuid': dev['image_id']})
                  self.db_lock.release()
                  if result <= 0:
                      error_text = "ERROR", result, content, "when getting image", dev['image_id']
                  else:
                      new_status = None
                  domain_dict[uuid] = new_status
 -            conn.close
 +            conn.close()
          except host_thread.lvirt_module.libvirtError as e:
              print self.name, ": get_state() Exception '", e.get_error_message()
              return
                      else:
                          new_status = 'ACTIVE'
                  elif 'start' in req['action']:
 -                    #La instancia está sólo en la base de datos pero no en la libvirt. es necesario crearla
 -                    rebuild = True if req['action']['start']=='rebuild'  else False
 +                    # The instance is only create in DB but not yet at libvirt domain, needs to be create
 +                    rebuild = True if req['action']['start'] == 'rebuild'  else False
                      r = self.launch_server(conn, req, rebuild, dom)
                      if r[0] <0:
                          new_status = 'ERROR'
          
                  conn.close()    
              except host_thread.lvirt_module.libvirtError as e:
 -                if conn is not None: conn.close
 +                if conn is not None: conn.close()
                  text = e.get_error_message()
                  new_status = "ERROR"
                  last_error = text
              ret=-1
          finally:
              if lib_conn is None and conn is not None:
 -                conn.close
 +                conn.close()
          return ret, error_text
  
          
                  print self.name, ": edit_iface(",port["instance_id"],") libvirt exception:", text 
                  
              finally:
 -                if conn is not None: conn.close
 -                            
 -                              
 +                if conn is not None: conn.close()
 +
 +
  def create_server(server, db, db_lock, only_of_ports):
      #print "server"
      #print "server"
          control_iface['net_id']=control_iface.pop('uuid')
          #Get the brifge name
          db_lock.acquire()
 -        result, content = db.get_table(FROM='nets', SELECT=('name','type', 'vlan'),WHERE={'uuid':control_iface['net_id']} )
 +        result, content = db.get_table(FROM='nets',
 +                                       SELECT=('name', 'type', 'vlan', 'provider', 'enable_dhcp',
 +                                                 'dhcp_first_ip', 'dhcp_last_ip', 'cidr'),
 +                                       WHERE={'uuid': control_iface['net_id']})
          db_lock.release()
          if result < 0: 
              pass
                  if network['type']!='bridge_data' and network['type']!='bridge_man':
                      return -1, "Error at field netwoks: network uuid %s for control interface is not of type bridge_man or bridge_data" % control_iface['net_id']
                  resources['bridged-ifaces'].append(control_iface)
 +                if network.get("provider") and network["provider"][0:3] == "OVS":
 +                    control_iface["type"] = "instance:ovs"
 +                else:
 +                    control_iface["type"] = "instance:bridge"
 +                if network.get("vlan"):
 +                    control_iface["vlan"] = network["vlan"]
 +
 +                if network.get("enable_dhcp") == 'true':
 +                    control_iface["enable_dhcp"] = network.get("enable_dhcp")
 +                    control_iface["dhcp_first_ip"] = network["dhcp_first_ip"]
 +                    control_iface["dhcp_last_ip"] = network["dhcp_last_ip"]
 +                    control_iface["cidr"] = network["cidr"]
              else:
                  if network['type']!='data' and network['type']!='ptp':
                      return -1, "Error at field netwoks: network uuid %s for dataplane interface is not of type data or ptp" % control_iface['net_id']
diff --combined httpserver.py
@@@ -26,8 -26,8 +26,8 @@@ This is the thread for the http server 
  Two thread will be launched, with normal and administrative permissions.
  '''
  
- __author__ = "Alfonso Tierno, Leonardo Mirabal"
- __date__ = "$10-jul-2014 12:07:15$"
 -__author__="Alfonso Tierno, Gerardo Garcia"
++__author__="Alfonso Tierno, Gerardo Garcia, Leonardo Mirabal"
+ __date__ ="$10-jul-2014 12:07:15$"
  
  import bottle
  import urlparse
@@@ -38,7 -38,6 +38,7 @@@ import datetim
  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
@@@ -75,6 -74,11 +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: 
@@@ -493,12 -497,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_)
          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/<host_id>', method='GET')
  def http_get_host_id(host_id):
@@@ -633,13 -633,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:
          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/<host_id>', method='PUT')
  def http_put_host_id(host_id):
      '''modify a host into the database. All resources are got and inserted'''
          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:
@@@ -877,13 -687,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}
@@@ -1238,13 -1044,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 inner join images on tenants_images.image_id=images.uuid'
-         where_['tenant_id'] = tenant_id
-     result, content = my.db.get_table(SELECT=select_, FROM=from_, WHERE=where_, LIMIT=limit_)
+         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_, 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)
@@@ -1263,14 -1070,15 +1269,15 @@@ def http_get_image_id(tenant_id, image_
          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
      else:
-         from_  ='tenants_images as ti inner join images as i on ti.image_id=i.uuid'
-         where_['tenant_id'] = tenant_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_, 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)
@@@ -1305,15 -1113,26 +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)
@@@ -1424,10 -1243,11 +1442,11 @@@ def http_put_image_id(tenant_id, image_
      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':
@@@ -1555,12 -1375,25 +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:
          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:
                  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
@@@ -1717,8 -1531,9 +1749,9 @@@ def http_server_action(server_id, tenan
                  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
      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:
                      #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)
  
  
@@@ -1854,7 -1659,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}
  
  @bottle.route(url_base + '/networks/<network_id>', 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)
          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',), 
              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():
      #check valid params
      net_provider = network.get('provider')
      net_type =     network.get('type')
-     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")
          net_type='bridge_man' 
          
      if net_provider != None:
-         if net_provider[:7] == 'bridge:':
+         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 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
              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
          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/<network_id>', method='PUT')
  def http_put_network_id(network_id):
      '''update a network_id into the database.'''
@@@ -2380,7 -2152,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':
@@@ -2459,4 -2231,3 +2492,3 @@@ def http_delete_port_id(port_id)
          bottle.abort(-result, content)
      return
      
diff --combined openvimd.cfg
@@@ -51,12 -51,12 +51,12 @@@ of_controller_dpid: '00:01:02:03:04:05:
  of_controller_nets_with_same_vlan: false         # (by default, true)
  
  #Server parameters
- http_host:       localhost           # IP address where openvim is listening (by default, localhost)
+ http_host:       0.0.0.0             # IP address where openvim is listening (by default, localhost)
  http_port:       9080                # General port where openvim is listening (by default, 9080)
  http_admin_port: 9085                # Admin port where openvim is listening (when missing, no administration server is launched)
  
  #database parameters
- db_host:   0.0.0.0                   # by default localhost
+ db_host:   localhost                   # by default localhost
  db_user:   vim                       # DB user
  db_passwd: vimpw                     # DB password
  db_name:   vim_db                    # Name of the VIM DB
@@@ -72,18 -72,8 +72,18 @@@ tenant_id: fc7b43b6-6bfa-11e4-84d2-5254
  network_vlan_range_start: 3000
  network_vlan_range_end:   4000
  
 +# Overlay network implementation. Options are:
 +# - ovs :   (by default) Use a vlxan mesh between computes to handle the network overlay.
 +# - bridge: Use pre-populated linux bridges with L2 conectivity at compte nodes.
 +network_type : ovs
 +ovs_controller_ip   :   localhost                   # dhcp controller IP address, must be change in order to
 +ovs_controller_user :   "osm_dhcp"                  # User for the dchp controller for OVS networks
 +ovs_controller_file_path  :   "/var/lib/openvim"    # Path for dhcp daemon configuration, by default '/var/lib/openvim'
 +
 +
  #host bridge interfaces for networks
 -# Openvim cannot create bridge networks automatically, in the same way as other CMS do.
 +# Apply only for 'network_type: bridge'
 +# Indicates the bridges at compute nodes to be used for the overlay networks
  # Bridge networks need to be pre-provisioned on each host and Openvim uses those pre-provisioned bridge networks.
  # Openvim assumes that the following bridge interfaces have been created on each host, appropriately associated to a physical port.
  # The following information needs to be provided:
  #    - The speed of the physical port in Gbps, where that bridge interface was created
  # For instance, next example assumes that 10 bridges have been created on each host
  # using vlans 2001 to 2010, associated to a 1Gbps physical port 
 -bridge_ifaces:
 -   #name:      [vlan, speed in Gbps]
 -   virbrMan1:  [2001, 1]
 -   virbrMan2:  [2002, 1]
 -   virbrMan3:  [2003, 1]
 -   virbrMan4:  [2004, 1]
 -   virbrMan5:  [2005, 1]
 -   virbrMan6:  [2006, 1]
 -   virbrMan7:  [2007, 1]
 -   virbrMan8:  [2008, 1]
 -   virbrMan9:  [2009, 1]
 -   virbrMan10: [2010, 1]
 +#bridge_ifaces:
 +#   #name:      [vlan, speed in Gbps]
 +#   virbrMan1:  [2001, 1]
 +#   virbrMan2:  [2002, 1]
 +#   virbrMan3:  [2003, 1]
 +#   virbrMan4:  [2004, 1]
 +#   virbrMan5:  [2005, 1]
 +#   virbrMan6:  [2006, 1]
 +#   virbrMan7:  [2007, 1]
 +#   virbrMan8:  [2008, 1]
 +#   virbrMan9:  [2009, 1]
 +#   virbrMan10: [2010, 1]
  
  #Used only when 'mode' is at development'. Indicates which 'bridge_ifaces' is used for dataplane networks
 -development_bridge: virbrMan10
 +#development_bridge: virbrMan10
  
  #DHCP SERVER PARAMETERS. 
  #In case some of the previous 'bridge_ifaces' are connected to an EXTERNAL dhcp server, provide 
@@@ -136,5 -126,3 +136,5 @@@ dhcp_server
  log_level:       ERROR
  log_level_db:    DEBUG
  log_level_of:    DEBUG
 +
 +
diff --combined openvimd.py
@@@ -30,9 -30,9 +30,9 @@@ and host controller
  
  __author__="Alfonso Tierno"
  __date__ ="$10-jul-2014 12:07:15$"
 -__version__="0.5.2-r516"
 +__version__="0.5.2-r519"
  version_date="Jan 2017"
--database_version="0.9"      #expected database schema version
++database_version="0.10"      #expected database schema version
  
  import httpserver
  import auxiliary_functions as af
@@@ -69,10 -69,6 +69,10 @@@ def load_configuration(configuration_fi
                       'log_level': "DEBUG",
                       'log_level_db': "ERROR",
                       'log_level_of': 'ERROR',
 +                     'bridge_ifaces': {},
 +                     'network_type': 'ovs',
 +                     'ovs_controller_user': 'osm_dhcp',
 +                     'ovs_controller_file_path': '/var/lib/',
              }
      try:
          #First load configuration from configuration file
@@@ -218,11 -214,10 +218,11 @@@ if __name__=="__main__"
              #allow backward compatibility of test_mode option
              if 'test_mode' in config_dic and config_dic['test_mode']==True:
                  config_dic['mode'] = 'test' 
 -        if config_dic['mode'] == 'development' and ( 'development_bridge' not in config_dic or config_dic['development_bridge'] not in config_dic.get("bridge_ifaces",None) ):
 +        if config_dic['mode'] == 'development' and config_dic['network_type'] == 'bridge' and \
 +                ( 'development_bridge' not in config_dic or config_dic['development_bridge'] not in config_dic.get("bridge_ifaces",None) ):
              logger.error("'%s' is not a valid 'development_bridge', not one of the 'bridge_ifaces'", config_file)
              exit(-1)
 -            
 +
          if config_dic['mode'] != 'normal':
              print '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
              print "!! Warning, openvimd in TEST mode '%s'" % config_dic['mode']
diff --combined vim_db.py
+++ b/vim_db.py
@@@ -37,7 -37,6 +37,7 @@@ import uuid as myUui
  import auxiliary_functions as af
  import json
  import logging
 +from netaddr import IPNetwork, IPSet, IPRange, all_matching_cidrs
  
  HTTP_Bad_Request = 400
  HTTP_Unauthorized = 401 
@@@ -174,7 -173,7 +174,7 @@@ class vim_db()
      def __get_used_net_vlan(self):
          #get used from database if needed
          try:
 -            cmd = "SELECT vlan FROM nets WHERE vlan>='%s' and (type='ptp' or type='data') ORDER BY vlan LIMIT 25" % self.net_vlan_lastused
 +            cmd = "SELECT vlan FROM nets WHERE vlan>='%s' ORDER BY vlan LIMIT 25" % self.net_vlan_lastused
              with self.con:
                  self.cur = self.con.cursor()
                  self.logger.debug(cmd)
              'WHERE': dict of key:values, translated to key=value AND ... (Optional)
              'WHERE_NOT': dict of key:values, translated to key!=value AND ... (Optional)
              'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
+             'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional)
              'LIMIT': limit of number of rows (Optional)
+             'DISTINCT': make a select distinct to remove repeated elements
          Return: a list with dictionarys at each row
          '''
          #print sql_dict
-         select_= "SELECT " + ("*" if 'SELECT' not in sql_dict else ",".join(map(str,sql_dict['SELECT'])) )
+         select_ = "SELECT "
+         if sql_dict.get("DISTINCT"):
+             select_ += "DISTINCT "
+         select_ += ("*" if 'SELECT' not in sql_dict else ",".join(map(str,sql_dict['SELECT'])) )
          #print 'select_', select_
          from_  = "FROM " + str(sql_dict['FROM'])
          #print 'from_', from_
          
          where_and = None
          where_or = None
-         if 'WHERE' in sql_dict and len(sql_dict['WHERE']) > 0:
-             w=sql_dict['WHERE']
-             where_and = " AND ".join(map( lambda x: str(x) + (" is Null" if w[x] is None else "='"+str(w[x])+"'"),  w.keys()) ) 
-         if 'WHERE_NOT' in sql_dict and len(sql_dict['WHERE_NOT']) > 0:
-             w=sql_dict['WHERE_NOT']
-             where_and_not = " AND ".join(map( lambda x: str(x) + (" is not Null" if w[x] is None else "!='"+str(w[x])+"'"),  w.keys()) ) 
+         w = sql_dict.get('WHERE')
+         if w:
+             where_and = " AND ".join(map( lambda x: str(x) + (" is Null" if w[x] is None else "='"+str(w[x])+"'"),  w.keys()) )
+         w = sql_dict.get('WHERE_NOT')
+         if w:
+             where_and_not = " AND ".join(map( lambda x: str(x) + (" is not Null" if w[x] is None else "!='"+str(w[x])+"'"),  w.keys()) )
              if where_and:
                  where_and += " AND " + where_and_not
              else:
                  where_and = where_and_not
-         if 'WHERE_OR' in sql_dict and len(sql_dict['WHERE_OR']) > 0:
-             w=sql_dict['WHERE_OR']
+         w = sql_dict.get('WHERE_OR')
+         if w:
              where_or =  " OR ".join(map( lambda x: str(x) + (" is Null" if w[x] is None else "='"+str(w[x])+"'"),  w.keys()) )
               
          if where_and!=None and where_or!=None:
-             where_ = "WHERE (" + where_and + ") OR " + where_or
+             if sql_dict.get("WHERE_AND_OR") == "AND":
+                 where_ = "WHERE " + where_and + " AND (" + where_or + ")"
+             else:
+                 where_ = "WHERE (" + where_and + ") OR " + where_or
          elif where_and!=None and where_or==None:
              where_ = "WHERE " + where_and
          elif where_and==None and where_or!=None:
                  with self.con:
                      self.cur = self.con.cursor(mdb.cursors.DictCursor)
                      #get INSTANCE
 -                    cmd = "SELECT uuid, name, description, progress, host_id, flavor_id, image_id, status, last_error, tenant_id, ram, vcpus, created_at \
 -                        FROM instances WHERE uuid = '" +  str(instance_id) +"'"
 +                    cmd = "SELECT uuid, name, description, progress, host_id, flavor_id, image_id, status, last_error, "\
 +                        "tenant_id, ram, vcpus, created_at FROM instances WHERE uuid='{}'".format(instance_id)
                      self.logger.debug(cmd)
                      self.cur.execute(cmd)
                      if self.cur.rowcount == 0 : return 0, "instance '" + str(instance_id) +"'not found."
                      instance = self.cur.fetchone()
                      #get networks
 -                    cmd = "SELECT uuid as iface_id, net_id, mac as mac_address, ip_address, name, Mbps as bandwidth, vpci, model \
 -                        FROM ports WHERE type = 'instance:bridge' AND instance_id = '" + instance_id + "'"
 +                    cmd = "SELECT uuid as iface_id, net_id, mac as mac_address, ip_address, name, Mbps as bandwidth, "\
 +                        "vpci, model FROM ports WHERE (type='instance:bridge' or type='instance:ovs') AND "\
 +                        "instance_id= '{}'".format(instance_id)
                      self.logger.debug(cmd)
                      self.cur.execute(cmd)
                      if self.cur.rowcount > 0 :
                                  numa_dict['threads-source'] = thread_source
  
                          #get dedicated ports and SRIOV
 -                        cmd = "SELECT port_id as iface_id, p.vlan as vlan, p.mac as mac_address, net_id, if(model='PF','yes',if(model='VF','no','yes:sriov')) as dedicated,\
 -                            rp.Mbps as bandwidth, name, vpci, pci as source \
 +                        cmd = "SELECT port_id as iface_id, p.vlan as vlan, p.mac as mac_address, net_id, if(model='PF',\
 +                            'yes',if(model='VF','no','yes:sriov')) as dedicated, rp.Mbps as bandwidth, name, vpci, \
 +                            pci as source \
                              FROM resources_port as rp join ports as p on port_id=uuid  WHERE p.instance_id = '%s' AND numa_id = '%s' and p.type='instance:data'" % (instance_id, numa_id) 
                          self.logger.debug(cmd)
                          self.cur.execute(cmd)
                      #insert resources
                      nb_bridge_ifaces = nb_cores = nb_ifaces = nb_numas = 0
                      #insert bridged_ifaces
 +
                      for iface in bridgedifaces:
                          #generate and insert a iface uuid
 +                        if 'enable_dhcp' in iface and iface['enable_dhcp']:
 +                            dhcp_first_ip = iface["dhcp_first_ip"]
 +                            del iface["dhcp_first_ip"]
 +                            dhcp_last_ip = iface["dhcp_last_ip"]
 +                            del iface["dhcp_last_ip"]
 +                            dhcp_cidr = iface["cidr"]
 +                            del iface["cidr"]
 +                            del iface["enable_dhcp"]
 +                            used_dhcp_ips = self._get_dhcp_ip_used_list(iface["net_id"])
 +                            iface["ip_address"] = self.get_free_ip_from_range(dhcp_first_ip, dhcp_last_ip,
 +                                                                              dhcp_cidr, used_dhcp_ips)
 +
                          iface['uuid'] = str(myUuid.uuid1()) # create_uuid
                          cmd = "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface['uuid'], uuid)
                          self.logger.debug(cmd)
                          self.cur.execute(cmd)
                          #insert iface
                          iface['instance_id'] = uuid
 -                        iface['type'] = 'instance:bridge'
 +                        iface['type'] = 'instance:bridge'
                          if 'name' not in iface: iface['name']="br"+str(nb_bridge_ifaces)
                          iface['Mbps']=iface.pop('bandwidth', None)
                          if 'mac_address' not in iface:
                  r,c = self.format_error(e, "new_instance", cmd)
                  if r!=-HTTP_Request_Timeout or retry_==1: return r,c
  
 -    def delete_instance(self, instance_id, tenant_id, net_list, ports_to_free, logcause="requested by http"):
 +    def get_free_ip_from_range(self, first_ip, last_ip, cidr, ip_used_list):
 +        """
 +        Calculate a free IP from a range given
 +        :param first_ip: First dhcp ip range
 +        :param last_ip: Last dhcp ip range
 +        :param cidr: net cidr
 +        :param ip_used_list: contain all used ips to avoid ip collisions
 +        :return:
 +        """
 +
 +        ip_tools = IPNetwork(cidr)
 +        cidr_len = ip_tools.prefixlen
 +        ips = IPNetwork(first_ip + '/' + str(cidr_len))
 +        ip_used_list.append(str(ips[0])) # first ip
 +        ip_used_list.append(str(ips[1])) # gw ip
 +        ip_used_list.append(str(ips[-1])) # broadcast ip
 +        for vm_ip in ips:
 +            if str(vm_ip) not in ip_used_list:
 +                return vm_ip
 +
 +        return None
 +
 +    def _get_dhcp_ip_used_list(self, net_id):
 +        """
 +        REtreive from DB all ips already used by the dhcp server for a given net
 +        :param net_id:
 +        :return:
 +        """
 +        WHERE={'type': 'instance:ovs', 'net_id': net_id}
 +        for retry_ in range(0, 2):
 +            cmd = ""
 +            self.cur = self.con.cursor(mdb.cursors.DictCursor)
 +            select_ = "SELECT uuid, ip_address FROM ports "
 +
 +            if WHERE is None or len(WHERE) == 0:
 +                where_ = ""
 +            else:
 +                where_ = "WHERE " + " AND ".join(
 +                    map(lambda x: str(x) + (" is Null" if WHERE[x] is None else "='" + str(WHERE[x]) + "'"),
 +                        WHERE.keys()))
 +            limit_ = "LIMIT 100"
 +            cmd = " ".join((select_, where_, limit_))
 +            self.logger.debug(cmd)
 +            self.cur.execute(cmd)
 +            ports = self.cur.fetchall()
 +            ip_address_list = []
 +            for port in ports:
 +                ip_address_list.append(port['ip_address'])
 +
 +            return ip_address_list
 +
 +
 +    def delete_instance(self, instance_id, tenant_id, net_dataplane_list, ports_to_free, net_ovs_list, logcause="requested by http"):
          for retry_ in range(0,2):
              cmd=""
              try:
                      self.cur.execute(cmd)
                      net_list__ = self.cur.fetchall()
                      for net in net_list__:
 -                        net_list.append(net[0])
 +                        net_dataplane_list.append(net[0])
 +
 +                    # get ovs manangement nets
 +                    cmd = "SELECT DISTINCT net_id, vlan, ip_address, mac FROM ports WHERE instance_id='{}' AND net_id is not Null AND "\
 +                            "type='instance:ovs'".format(instance_id)
 +                    self.logger.debug(cmd)
 +                    self.cur.execute(cmd)
 +                    net_ovs_list += self.cur.fetchall()
  
                      #get dataplane interfaces releases by this VM; both PF and VF with no other VF 
                      cmd="SELECT source_name, mac FROM (SELECT root_id, count(instance_id) as used FROM resources_port WHERE instance_id='%s' GROUP BY root_id ) AS A" % instance_id \
              if net['tenant_id']==tenant_id and net['shared']=='false':
                  return -1, "needed admin privileges to attach to the net %s" % net_id
          #check types
 -        if (net['type'] in ('p2p','data') and 'port_type' == 'instance:bridge') or \
 -            (net['type'] in ('bridge_data','bridge_man') and 'port_type' != 'instance:bridge') :
 +        if (net['type'] in ('p2p','data') and port_type != 'instance:data') or \
 +            (net['type'] in ('bridge_data','bridge_man') and port_type not in ('instance:bridge', 'instance:ovs')):
              return -1, "can not attach a port of type %s into a net of type %s" % (port_type, net['type'])
          if net['type'] == 'ptp':
              #look how many