Openvim managment nets OVS refactoring 17/817/11
authorMirabal <leonardo.mirabal@altran.com>
Thu, 15 Dec 2016 10:51:19 +0000 (10:51 +0000)
committerMirabal <leonardo.mirabal@altran.com>
Wed, 18 Jan 2017 13:29:31 +0000 (13:29 +0000)
- OVS bridge creation and vxlan tunnel mesh (stp active) creation in openvim hosts.
- Add/remove/edit nets handling OVS ports, dhcp nets are supported to keep backwards compatibility.

Change-Id: I971067c77e50df292fa5cdd3bf926a222af349aa
Signed-off-by: Mirabal <leonardo.mirabal@altran.com>
host_thread.py
httpserver.py
openvimd.cfg
openvimd.py
vim_db.py
vim_schema.py

index 173634b..bb3a433 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
@@ -45,10 +44,12 @@ import random
 
 #TODO: insert a logging system
 
-global lvirt_module
-lvirt_module=None  #libvirt module is charged only if not in test mode
+
+#global lvirt_module
+#lvirt_module=None  #libvirt module is charged only if not in test mode
 
 class host_thread(threading.Thread):
+    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: 
@@ -64,9 +65,11 @@ class host_thread(threading.Thread):
         self.db = db
         self.db_lock = db_lock
         self.test = test
-        if not test:
+
+        if not test and not host_thread.lvirt_module:
             try:
-                lvirt_module = imp.find_module("libvirt")
+                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))
 
@@ -88,7 +91,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
@@ -131,7 +135,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 lvirt_module.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:
@@ -176,7 +180,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 lvirt_module.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:
@@ -217,7 +221,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 lvirt_module.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:
@@ -331,6 +335,27 @@ 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()
+                    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
                 
@@ -589,6 +614,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:
@@ -677,7 +706,182 @@ 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
+        """
+        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:
+        """
+
+        command = 'sudo ovs-vsctl del-port br-int ovim-' + 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 is_port_free(self, vlan, net_uuid):
+        """
+        Check if por is free before delete from the compute.
+        :param vlan: vlan port 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:bridge', 'p.net_id':  net_uuid}
+        )
+        self.db_lock.release()
+
+        if 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:
+        """
+        command = 'sudo ovs-vsctl add-port br-int ovim-' + vlan + ' 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_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 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
+        """
+        command = 'sudo ifconfig ovim-' + vlan + ' down &&  sudo brctl delbr ovim-' + 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 create_ovs_bridge_port(self, vlan):
+        """
+        Generate a linux bridge and attache the port to a OVS bridge
+        :param vlan: vlan port id
+        :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:
+        """
+        command = 'sudo brctl addbr ovim-' + vlan + ' && sudo ifconfig ovim-' + vlan + ' up'
+        print self.name, ': command:', command
+        (_, stdout, _) = self.ssh_conn.exec_command(command)
+        content = stdout.read()
+
+        if len(content) != 0:
+            return False
+
+        command = 'sudo brctl stp ovim-' + vlan + ' 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
+
+    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:
+        """
+        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.
+        """
+        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
+        """
+        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
@@ -944,7 +1148,7 @@ class host_thread(threading.Thread):
                 print self.name, ": create xml server error:", xml
                 return -2, xml
             print self.name, ": create xml:", xml
-            atribute = lvirt_module.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)
@@ -959,7 +1163,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 lvirt_module.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:
@@ -982,26 +1186,26 @@ class host_thread(threading.Thread):
             return            
         
         try:
-            conn = lvirt_module.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] == lvirt_module.VIR_DOMAIN_RUNNING or libvirt_status[0] == lvirt_module.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] == lvirt_module.VIR_DOMAIN_PAUSED:
+                elif libvirt_status[0] == host_thread.lvirt_module.VIR_DOMAIN_PAUSED:
                     new_status = "PAUSED"
-                elif libvirt_status[0] == lvirt_module.VIR_DOMAIN_SHUTOFF:
+                elif libvirt_status[0] == host_thread.lvirt_module.VIR_DOMAIN_SHUTOFF:
                     new_status = "INACTIVE"
-                elif libvirt_status[0] == lvirt_module.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 lvirt_module.libvirtError as e:
+            conn.close()
+        except host_thread.lvirt_module.libvirtError as e:
             print self.name, ": get_state() Exception '", e.get_error_message()
             return
 
@@ -1067,10 +1271,10 @@ class host_thread(threading.Thread):
                 self.create_image(None, req)
         else:
             try:
-                conn = lvirt_module.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 lvirt_module.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
@@ -1152,8 +1356,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'
@@ -1196,8 +1400,8 @@ class host_thread(threading.Thread):
                         
         
                 conn.close()    
-            except lvirt_module.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
@@ -1253,7 +1457,7 @@ class host_thread(threading.Thread):
             return 0, None
         try:
             if not lib_conn:
-                conn = lvirt_module.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
                 
@@ -1264,13 +1468,13 @@ class host_thread(threading.Thread):
             iface.destroy()
             iface.create()
             print self.name, ": restore_iface '%s' %s" % (name, mac)
-        except lvirt_module.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
 
         
@@ -1354,12 +1558,12 @@ class host_thread(threading.Thread):
             
             try:
                 conn=None
-                conn = lvirt_module.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=lvirt_module.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
@@ -1367,14 +1571,14 @@ 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=lvirt_module.VIR_DOMAIN_AFFECT_LIVE)
+                    dom.attachDeviceFlags(text, flags=host_thread.lvirt_module.VIR_DOMAIN_AFFECT_LIVE)
                     
-            except lvirt_module.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):
index ecf878c..e5ce5cd 100644 (file)
@@ -26,8 +26,8 @@ This is the thread for the http server North API.
 Two thread will be launched, with normal and administrative permissions.
 '''
 
-__author__="Alfonso Tierno"
-__date__ ="$10-jul-2014 12:07:15$"
+__author__ = "Alfonso Tierno, Leonardo Mirabal"
+__date__ = "$10-jul-2014 12:07:15$"
 
 import bottle
 import urlparse
@@ -492,8 +492,12 @@ def enable_cors():
 
 @bottle.route(url_base + '/hosts', method='GET')
 def http_get_hosts():
-    select_,where_,limit_ = filter_query_string(bottle.request.query, http2db_host,
-            ('id','name','description','status','admin_state_up') )
+    return format_out(get_hosts())
+
+
+def get_hosts():
+    select_, where_, limit_ = filter_query_string(bottle.request.query, http2db_host,
+                                                  ('id', 'name', 'description', 'status', 'admin_state_up', 'ip_name'))
     
     myself = config_dic['http_threads'][ threading.current_thread().name ]
     result, content = myself.db.get_table(FROM='hosts', SELECT=select_, WHERE=where_, LIMIT=limit_)
@@ -506,7 +510,7 @@ def http_get_hosts():
         for row in content:
             row['links'] = ( {'href': myself.url_preffix + '/hosts/' + str(row['id']), 'rel': 'bookmark'}, )
         data={'hosts' : content}
-        return format_out(data)
+        return data
 
 @bottle.route(url_base + '/hosts/<host_id>', method='GET')
 def http_get_host_id(host_id):
@@ -628,6 +632,12 @@ def http_post_hosts():
             thread.start()
             config_dic['host_threads'][ content['uuid'] ] = thread
 
+            if config_dic['network_type'] == 'ovs':
+                # create bridge
+                config_dic['host_threads'][content['uuid']].insert_task("new-ovsbridge")
+                # check if more host exist
+                create_vxlan_mesh(content['uuid'])
+
         #return host data
         change_keys_http2db(content, http2db_host, reverse=True)
         if len(warning_text)>0:
@@ -638,6 +648,50 @@ def http_post_hosts():
         bottle.abort(HTTP_Bad_Request, content)
         return
 
+
+def create_vxlan_mesh(host_id):
+    existing_hosts = get_hosts()
+    if len(existing_hosts['hosts']) > 1:
+        computes_available = existing_hosts['hosts']
+
+        # TUNEL openvim controller
+
+        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])
+                    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])
+
+    for compute in computes_available:
+        if host_id == compute['id']:
+            pass
+        else:
+            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'''
@@ -659,12 +713,21 @@ def http_put_host_id(host_id):
         change_keys_http2db(content, http2db_host, reverse=True)
         data={'host' : content}
 
+        if config_dic['network_type'] == 'ovs':
+            delete_vxlan_mesh(host_id)
+            config_dic['host_threads'][host_id].insert_task("del-ovsbridge")
+
         #reload thread
         config_dic['host_threads'][host_id].name = content.get('name',content['ip_name'])
         config_dic['host_threads'][host_id].user = content['user']
         config_dic['host_threads'][host_id].host = content['ip_name']
         config_dic['host_threads'][host_id].insert_task("reload")
 
+        if config_dic['network_type'] == 'ovs':
+            # create mesh with new host data
+            config_dic['host_threads'][host_id].insert_task("new-ovsbridge")
+            create_vxlan_mesh(host_id)
+
         #print data
         return format_out(data)
     else:
@@ -682,9 +745,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}
@@ -1413,7 +1480,11 @@ def http_post_server_id(tenant_id):
     #Start server
         
         server['uuid'] = new_instance
-        #server_start = server.get('start', 'yes')
+        # server_start = server.get('start', 'yes')
+        if config_dic['network_type'] == 'ovs':
+            server_net = get_network_id(c2[0]['net_id'])
+            vlan = str(server_net['network']['provider:vlan'])
+            config_dic['host_threads'][server['host_id']].insert_task("create-ovs-bridge-port", vlan)
         if server_start != 'no':
             server['paused'] = True if server_start == 'paused' else False 
             server['action'] = {"start":None}
@@ -1552,9 +1623,11 @@ def http_server_action(server_id, tenant_id, action):
     if new_status != None and new_status == 'DELETING':
         nets=[]
         ports_to_free=[]
-        #look for dhcp ip address 
+
+        net_ovs_list = []
+        #look for dhcp ip address
         r2, c2 = my.db.get_table(FROM="ports", SELECT=["mac", "net_id"], WHERE={"instance_id": server_id})
-        r,c = my.db.delete_instance(server_id, tenant_id, nets, ports_to_free, "requested by http")
+        r, c = my.db.delete_instance(server_id, tenant_id, nets, ports_to_free, net_ovs_list, "requested by http")
         for port in ports_to_free:
             r1,c1 = config_dic['host_threads'][ server['host_id'] ].insert_task( 'restore-iface',*port )
             if r1 < 0:
@@ -1573,7 +1646,12 @@ def http_server_action(server_id, tenant_id, action):
                     #print "dhcp insert del task"
                     if r < 0:
                         print ':http_post_servers ERROR UPDATING dhcp_server !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' +  c 
-
+        if config_dic['network_type'] == 'ovs':
+            # delete ovs-port and linux bridge
+            for net in net_ovs_list:
+                server_net = get_network_id(net)
+                vlan = str(server_net['network']['provider:vlan'])
+                config_dic['host_threads'][server['host_id']].insert_task('del-ovs-port', vlan, server_net['network']['id'])
     return format_out(data)
 
 
@@ -1634,8 +1712,12 @@ def http_get_networks():
 
 @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)
@@ -1656,7 +1738,7 @@ def http_get_network_id(network_id):
             content[0]['ports'] = ports
         delete_nulls(content[0])      
         data={'network' : content[0]}
-        return format_out(data)
+        return data
 
 @bottle.route(url_base + '/networks', method='POST')
 def http_post_networks():
@@ -1739,8 +1821,7 @@ def http_post_networks():
         net_type='bridge_man' 
         
     if net_provider != None:
-        if net_provider[:7]=='bridge:':
-            #check it is one of the pre-provisioned bridges
+        if net_provider[:7] == 'bridge:':
             bridge_net_name = net_provider[7:]
             for brnet in config_dic['bridge_nets']:
                 if brnet[0]==bridge_net_name: # free
@@ -1753,7 +1834,7 @@ def http_post_networks():
 #            if bridge_net==None:     
 #                bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
 #                return
-    elif net_type=='bridge_data' or net_type=='bridge_man':
+    elif config_dic['network_type'] == 'bridge' and net_type =='bridge_data' or net_type ==  'bridge_man' :
         #look for a free precreated nets
         for brnet in config_dic['bridge_nets']:
             if brnet[3]==None: # free
@@ -1772,12 +1853,16 @@ def http_post_networks():
             print "using net", bridge_net
             net_provider = "bridge:"+bridge_net[0]
             net_vlan = bridge_net[1]
-    if net_vlan==None and (net_type=="data" or net_type=="ptp"):
+    elif net_type == 'bridge_data' or net_type == 'bridge_man' and config_dic['network_type'] == 'ovs':
+        net_provider = 'OVS'
+    if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
         net_vlan = my.db.get_free_net_vlan()
         if net_vlan < 0:
             bottle.abort(HTTP_Internal_Server_Error, "Error getting an available vlan")
             return
-    
+    if config_dic['network_type'] == 'ovs':
+        net_provider = 'OVS' + ":" + str(net_vlan)
+
     network['provider'] = net_provider
     network['type']     = net_type
     network['vlan']     = net_vlan
@@ -1787,7 +1872,7 @@ def http_post_networks():
         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
index 2d1aabb..bfa937a 100644 (file)
@@ -72,8 +72,14 @@ tenant_id: fc7b43b6-6bfa-11e4-84d2-5254006d6777   # Default tenant identifier fo
 network_vlan_range_start: 3000
 network_vlan_range_end:   4000
 
+# Network overlay supported by openvim compute, bsae on openvswicth or linux bridges to manage management networks for NFVs.
+# - ovs : Create a vlxan mesh between computes to handle the network overlay, no prepopulated bridges or networks is need it.
+# - bridge: Use pre-populate linux bridges by openvim configuration scripts.
+
+network_type : ovs
+
 #host bridge interfaces for networks
-# Openvim cannot create bridge networks automatically, in the same way as other CMS do.
+# Openvim cannot create bridge networks automatically, in the same way as other CMS do when network type is "bridge".
 # 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:
@@ -82,21 +88,21 @@ network_vlan_range_end:   4000
 #    - 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 
@@ -126,3 +132,5 @@ dhcp_server:
 log_level:       ERROR
 log_level_db:    DEBUG
 log_level_of:    DEBUG
+
+
index 6513943..573ce27 100755 (executable)
@@ -69,6 +69,8 @@ def load_configuration(configuration_file):
                      'log_level': "DEBUG",
                      'log_level_db': "ERROR",
                      'log_level_of': 'ERROR',
+                     'bridge_ifaces': {},
+                     'network_type': 'ovs',
             }
     try:
         #First load configuration from configuration file
@@ -214,7 +216,8 @@ 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)
             
index d88306d..dbb8ffe 100644 (file)
--- a/vim_db.py
+++ b/vim_db.py
@@ -1495,7 +1495,7 @@ class vim_db():
                 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 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:
@@ -1515,7 +1515,16 @@ class vim_db():
                     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 from ports WHERE instance_id = " \
+                          "'%s' AND net_id is not Null AND type='instance:bridge'" % instance_id
+                    self.logger.debug(cmd)
+                    self.cur.execute(cmd)
+                    net_list__ = self.cur.fetchall()
+                    for net in net_list__:
+                        net_ovs_list.append(net[0])
 
                     #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 \
index 0a5929d..5bf555d 100644 (file)
@@ -117,12 +117,13 @@ config_schema = {
         "log_level": log_level_schema,
         "log_level_db": log_level_schema,
         "log_level_of": log_level_schema,
+        "network_type": {"type": "string", "enum": ["ovs", "bridge"]},
     },
     "patternProperties": {
         "of_*" : {"type": ["string", "integer", "boolean"]}
     },
     "required": ['db_host', 'db_user', 'db_passwd', 'db_name',
-            'of_controller_ip', 'of_controller_port', 'of_controller_dpid', 'bridge_ifaces', 'of_controller'],
+            'of_controller_ip', 'of_controller_port', 'of_controller_dpid', 'of_controller'],
     "additionalProperties": False
 }