Add openflow-port-mapping CLI command
[osm/openvim.git] / host_thread.py
index cae8c60..d8bca2e 100644 (file)
@@ -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
@@ -36,18 +35,27 @@ import time
 import Queue
 import paramiko
 from jsonschema import validate as js_v, exceptions as js_e
-import libvirt
+#import libvirt
+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
+
+
 class host_thread(threading.Thread):
-    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
@@ -60,6 +68,15 @@ class host_thread(threading.Thread):
         self.db = db
         self.db_lock = db_lock
         self.test = test
+
+        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)
+            except (IOError, ImportError) as e:
+                raise ImportError("Cannot import python-libvirt. Openvim not properly installed" +str(e))
+
+
         self.develop_mode = develop_mode
         self.develop_bridge_iface = develop_bridge_iface
         self.image_path = image_path
@@ -77,7 +94,8 @@ class host_thread(threading.Thread):
         
         self.queueLock = threading.Lock()
         self.taskQueue = Queue.Queue(2000)
-        
+        self.ssh_conn = None
+
     def ssh_connect(self):
         try:
             #Connect SSH
@@ -120,7 +138,7 @@ class host_thread(threading.Thread):
             except paramiko.ssh_exception.SSHException as e:
                 text = e.args[0]
                 print self.name, ": load_localinfo ssh Exception:", text
-            except libvirt.libvirtError as e:
+            except host_thread.lvirt_module.libvirtError as e:
                 text = e.get_error_message()
                 print self.name, ": load_localinfo libvirt Exception:", text
             except yaml.YAMLError as exc:
@@ -165,7 +183,7 @@ class host_thread(threading.Thread):
         except paramiko.ssh_exception.SSHException as e:
             text = e.args[0]
             print self.name, ": load_hostinfo ssh Exception:", text
-        except libvirt.libvirtError as e:
+        except host_thread.lvirt_module.libvirtError as e:
             text = e.get_error_message()
             print self.name, ": load_hostinfo libvirt Exception:", text
         except yaml.YAMLError as exc:
@@ -206,7 +224,7 @@ class host_thread(threading.Thread):
                 print self.name, ": save_localinfo ssh Exception:", text
                 if "SSH session not active" in text:
                     self.ssh_connect()
-            except libvirt.libvirtError as e:
+            except host_thread.lvirt_module.libvirtError as e:
                 text = e.get_error_message()
                 print self.name, ": save_localinfo libvirt Exception:", text
             except yaml.YAMLError as exc:
@@ -320,6 +338,24 @@ class host_thread(threading.Thread):
                 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()
+                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])
+                elif task[0] == 'del-ovsbridge':
+                    print self.name, ": Deleting OVS bridge"
+                    self.delete_ovs_bridge()
+                elif task[0] == 'del-vxlan':
+                    print self.name, ": Deleting vxlan " + task[1] + " tunnel"
+                    self.delete_ovs_vxlan_tunnel(task[1])
+                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':
+                    print self.name, ": Delete bridge attached to ovs port vlan {} net {}".format(task[1], task[2])
+                    self.delete_bridge_port_attached_to_ovs(task[1], task[2])
                 else:
                     print self.name, ": unknown task", task
                 
@@ -465,8 +501,12 @@ class host_thread(threading.Thread):
             self.tab()+'<apic/>' +\
             self.tab()+'<pae/>'+ \
             self.dec_tab() +'</features>'
-        if windows_os or topo=="oneSocket":
-            text += self.tab() + "<cpu mode='host-model'> <topology sockets='1' cores='%d' threads='1' /> </cpu>"% vcpus
+        if topo == "oneSocket:hyperthreading":
+            if vcpus % 2 != 0:
+                return -1, 'Cannot expose hyperthreading with an odd number of vcpus'
+            text += self.tab() + "<cpu mode='host-model'> <topology sockets='1' cores='%d' threads='2' /> </cpu>" % vcpus/2
+        elif windows_os or topo == "oneSocket":
+            text += self.tab() + "<cpu mode='host-model'> <topology sockets='1' cores='%d' threads='1' /> </cpu>" % vcpus
         else:
             text += self.tab() + "<cpu mode='host-model'></cpu>"
         text += self.tab() + "<clock offset='utc'/>" +\
@@ -578,6 +618,10 @@ class host_thread(threading.Thread):
                         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:
@@ -666,7 +710,519 @@ class host_thread(threading.Thread):
         """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, gateway):
+        """
+        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
+        :param gateway: Gateway address for dhcp net
+        :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 ' + gateway
+
+        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
@@ -757,9 +1313,14 @@ class host_thread(threading.Thread):
             raise paramiko.ssh_exception.SSHException("Error deleting file: " + error_msg)
 
     def copy_file(self, source, destination, perserve_time=True):
-        command = 'cp --no-preserve=mode '
-        if perserve_time: command += '--preserve=timestamps '
-        command +=  source + ' '  + destination
+        if source[0:4]=="http":
+            command = "wget --no-verbose -O '{dst}' '{src}' 2>'{dst_result}' || cat '{dst_result}' >&2 && rm '{dst_result}'".format(
+                dst=destination, src=source, dst_result=destination + ".result" )
+        else:
+            command = 'cp --no-preserve=mode'
+            if perserve_time:
+                command += ' --preserve=timestamps'
+            command +=  " '{}' '{}'".format(source, destination)
         print self.name, ': command:', command
         (_, _, stderr) = self.ssh_conn.exec_command(command)
         error_msg = stderr.read()
@@ -783,24 +1344,29 @@ class host_thread(threading.Thread):
         use_incremental_out = use_incremental
         new_backing_file = None
         local_file = None
+        file_from_local = True
 
         #in case incremental use is not decided, take the decision depending on the image
         #avoid the use of incremental if this image is already incremental
-        qemu_remote_info = self.qemu_get_info(remote_file)
+        if remote_file[0:4] == "http":
+            file_from_local = False
+        if file_from_local:
+            qemu_remote_info = self.qemu_get_info(remote_file)
         if use_incremental_out==None:
-            use_incremental_out = not 'backing file' in qemu_remote_info
+            use_incremental_out = not ( file_from_local and 'backing file' in qemu_remote_info)
         #copy recursivelly the backing files
-        if 'backing file' in qemu_remote_info:
+        if  file_from_local and 'backing file' in qemu_remote_info:
             new_backing_file, _, _ = self.copy_remote_file(qemu_remote_info['backing file'], True)
         
         #check if remote file is present locally
         if use_incremental_out and remote_file in self.localinfo['files']:
             local_file = self.localinfo['files'][remote_file]
             local_file_info =  self.get_file_info(local_file)
-            remote_file_info = self.get_file_info(remote_file)
+            if file_from_local:
+                remote_file_info = self.get_file_info(remote_file)
             if local_file_info == None:
                 local_file = None
-            elif local_file_info[4]!=remote_file_info[4] or local_file_info[5]!=remote_file_info[5]:
+            elif file_from_local and (local_file_info[4]!=remote_file_info[4] or local_file_info[5]!=remote_file_info[5]):
                 #local copy of file not valid because date or size are different. 
                 #TODO DELETE local file if this file is not used by any active virtual machine
                 try:
@@ -874,7 +1440,8 @@ class host_thread(threading.Thread):
                     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']
@@ -923,7 +1490,7 @@ class host_thread(threading.Thread):
                 print self.name, ": create xml server error:", xml
                 return -2, xml
             print self.name, ": create xml:", xml
-            atribute = libvirt.VIR_DOMAIN_START_PAUSED if paused == "yes" else 0
+            atribute = host_thread.lvirt_module.VIR_DOMAIN_START_PAUSED if paused == "yes" else 0
         #4 Start the domain
             if not rebuild: #ensures that any pending destroying server is done
                 self.server_forceoff(True)
@@ -938,7 +1505,7 @@ class host_thread(threading.Thread):
             print self.name, ": launch_server(%s) ssh Exception: %s" %(server_id, text)
             if "SSH session not active" in text:
                 self.ssh_connect()
-        except libvirt.libvirtError as e:
+        except host_thread.lvirt_module.libvirtError as e:
             text = e.get_error_message()
             print self.name, ": launch_server(%s) libvirt Exception: %s"  %(server_id, text)
         except Exception as e:
@@ -961,26 +1528,26 @@ class host_thread(threading.Thread):
             return            
         
         try:
-            conn = libvirt.open("qemu+ssh://"+self.user+"@"+self.host+"/system")
+            conn = host_thread.lvirt_module.open("qemu+ssh://"+self.user+"@"+self.host+"/system")
             domains=  conn.listAllDomains() 
             domain_dict={}
             for domain in domains:
                 uuid = domain.UUIDString() ;
                 libvirt_status = domain.state()
                 #print libvirt_status
-                if libvirt_status[0] == libvirt.VIR_DOMAIN_RUNNING or libvirt_status[0] == libvirt.VIR_DOMAIN_SHUTDOWN:
+                if libvirt_status[0] == host_thread.lvirt_module.VIR_DOMAIN_RUNNING or libvirt_status[0] == host_thread.lvirt_module.VIR_DOMAIN_SHUTDOWN:
                     new_status = "ACTIVE"
-                elif libvirt_status[0] == libvirt.VIR_DOMAIN_PAUSED:
+                elif libvirt_status[0] == host_thread.lvirt_module.VIR_DOMAIN_PAUSED:
                     new_status = "PAUSED"
-                elif libvirt_status[0] == libvirt.VIR_DOMAIN_SHUTOFF:
+                elif libvirt_status[0] == host_thread.lvirt_module.VIR_DOMAIN_SHUTOFF:
                     new_status = "INACTIVE"
-                elif libvirt_status[0] == libvirt.VIR_DOMAIN_CRASHED:
+                elif libvirt_status[0] == host_thread.lvirt_module.VIR_DOMAIN_CRASHED:
                     new_status = "ERROR"
                 else:
                     new_status = None
                 domain_dict[uuid] = new_status
-            conn.close
-        except libvirt.libvirtError as e:
+            conn.close()
+        except host_thread.lvirt_module.libvirtError as e:
             print self.name, ": get_state() Exception '", e.get_error_message()
             return
 
@@ -1046,15 +1613,15 @@ class host_thread(threading.Thread):
                 self.create_image(None, req)
         else:
             try:
-                conn = libvirt.open("qemu+ssh://"+self.user+"@"+self.host+"/system")
+                conn = host_thread.lvirt_module.open("qemu+ssh://"+self.user+"@"+self.host+"/system")
                 try:
                     dom = conn.lookupByUUIDString(server_id)
-                except libvirt.libvirtError as e:
+                except host_thread.lvirt_module.libvirtError as e:
                     text = e.get_error_message()
                     if 'LookupByUUIDString' in text or 'Domain not found' in text or 'No existe un dominio coincidente' in text:
                         dom = None
                     else:
-                        print self.name, ": action_on_server(",server_id,") libvirt exception:", text 
+                        print self.name, ": action_on_server(",server_id,") libvirt exception:", text
                         raise e
                 
                 if 'forceOff' in req['action']:
@@ -1131,8 +1698,8 @@ class host_thread(threading.Thread):
                     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'
@@ -1175,8 +1742,8 @@ class host_thread(threading.Thread):
                         
         
                 conn.close()    
-            except libvirt.libvirtError as e:
-                if conn is not None: conn.close
+            except host_thread.lvirt_module.libvirtError as e:
+                if conn is not None: conn.close()
                 text = e.get_error_message()
                 new_status = "ERROR"
                 last_error = text
@@ -1232,7 +1799,7 @@ class host_thread(threading.Thread):
             return 0, None
         try:
             if not lib_conn:
-                conn = libvirt.open("qemu+ssh://"+self.user+"@"+self.host+"/system")
+                conn = host_thread.lvirt_module.open("qemu+ssh://"+self.user+"@"+self.host+"/system")
             else:
                 conn = lib_conn
                 
@@ -1243,13 +1810,13 @@ class host_thread(threading.Thread):
             iface.destroy()
             iface.create()
             print self.name, ": restore_iface '%s' %s" % (name, mac)
-        except libvirt.libvirtError as e:   
+        except host_thread.lvirt_module.libvirtError as e:
             error_text = e.get_error_message()
             print self.name, ": restore_iface '%s' '%s' libvirt exception: %s" %(name, mac, error_text) 
             ret=-1
         finally:
             if lib_conn is None and conn is not None:
-                conn.close
+                conn.close()
         return ret, error_text
 
         
@@ -1333,12 +1900,12 @@ class host_thread(threading.Thread):
             
             try:
                 conn=None
-                conn = libvirt.open("qemu+ssh://"+self.user+"@"+self.host+"/system")
+                conn = host_thread.lvirt_module.open("qemu+ssh://"+self.user+"@"+self.host+"/system")
                 dom = conn.lookupByUUIDString(port["instance_id"])
                 if old_net:
                     text="\n".join(xml)
                     print self.name, ": edit_iface detaching SRIOV interface", text
-                    dom.detachDeviceFlags(text, flags=libvirt.VIR_DOMAIN_AFFECT_LIVE)
+                    dom.detachDeviceFlags(text, flags=host_thread.lvirt_module.VIR_DOMAIN_AFFECT_LIVE)
                 if new_net:
                     xml[-1] ="  <vlan>   <tag id='" + str(port['vlan']) + "'/>   </vlan>"
                     self.xml_level = 1
@@ -1346,16 +1913,16 @@ class host_thread(threading.Thread):
                     xml.append('</interface>')                
                     text="\n".join(xml)
                     print self.name, ": edit_iface attaching SRIOV interface", text
-                    dom.attachDeviceFlags(text, flags=libvirt.VIR_DOMAIN_AFFECT_LIVE)
+                    dom.attachDeviceFlags(text, flags=host_thread.lvirt_module.VIR_DOMAIN_AFFECT_LIVE)
                     
-            except libvirt.libvirtError as e:
+            except host_thread.lvirt_module.libvirtError as e:
                 text = e.get_error_message()
                 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"
@@ -1622,7 +2189,10 @@ def create_server(server, db, db_lock, only_of_ports):
         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
@@ -1634,6 +2204,18 @@ def create_server(server, db, db_lock, only_of_ports):
                 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']