Bug 462 (Enhancement) - Add support for Xen and Unikernels
[osm/openvim.git] / osm_openvim / vim_db.py
index b034342..abeb0fd 100644 (file)
@@ -37,7 +37,7 @@ import uuid as myUuid
 import auxiliary_functions as af
 import json
 import logging
-from netaddr import IPNetwork, IPSet, IPRange, all_matching_cidrs
+from netaddr import IPNetwork, IPAddress
 
 HTTP_Bad_Request = 400
 HTTP_Unauthorized = 401 
@@ -136,8 +136,10 @@ class vim_db():
                 
         self.logger.error("%s DB Exception %s. Command %s",func, str(e), cmd)
         if type(e[0]) is str:
-            if e[0][-5:] == "'con'": return -HTTP_Internal_Server_Error, "DB Exception, no connection."
-            else: raise
+            if e[0][-5:] == "'con'":
+                return -HTTP_Internal_Server_Error, "DB Exception, no connection."
+            else:
+                return -HTTP_Internal_Server_Error, e.args[1]
         if e.args[0]==2006 or e.args[0]==2013 : #MySQL server has gone away (((or)))    Exception 2013: Lost connection to MySQL server during query
             #reconnect
             self.connect()
@@ -246,6 +248,13 @@ class vim_db():
         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_LIKE')  #Unikernels extension -START-
+        if w:
+            where_and_like = " AND ".join(map( lambda x: str(x) + (" is Null" if w[x] is None else " LIKE '"+str(w[x])+"'"),  w.keys()) )
+            if where_and:
+                where_and += " AND " + where_and_like
+            else:
+                where_and = where_and_like  #Unikernels extension -END-
         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()) )
@@ -472,16 +481,19 @@ class vim_db():
                 with self.con:
                     self.cur = self.con.cursor(mdb.cursors.DictCursor)
                     #get HOST
-                    cmd = "SELECT uuid, user, name, ip_name, description, ranking, admin_state_up, DATE_FORMAT(created_at,'%Y-%m-%dT%H:%i:%s') as created_at \
-                        FROM hosts WHERE " + where_filter
+                    cmd = "SELECT uuid, user, password, keyfile, name, ip_name, description, hypervisors, ranking, admin_state_up, "\
+                          "DATE_FORMAT(created_at,'%Y-%m-%dT%H:%i:%s') as created_at "\
+                          "FROM hosts WHERE " + where_filter  #Unikernels extension
                     self.logger.debug(cmd) 
                     self.cur.execute(cmd)
-                    if self.cur.rowcount == 0 : 
+                    if self.cur.rowcount == 0:
                         return 0, "host '" + str(host_id) +"'not found."
                     elif self.cur.rowcount > 1 : 
                         return 0, "host '" + str(host_id) +"' matches more than one result."
                     host = self.cur.fetchone()
                     host_id = host['uuid']
+                    if host.get("password"):
+                        host["password"] = "*****"
                     #get numa
                     cmd = "SELECT id, numa_socket, hugepages, memory, admin_state_up FROM numas WHERE host_id = '" + str(host_id) + "'"
                     self.logger.debug(cmd)
@@ -504,20 +516,20 @@ class vim_db():
                         used = self.cur.fetchone()
                         used_= int(used['hugepages_consumed']) if used != None else 0
                         numa['hugepages_consumed'] = used_
-                        #get ports
-                        #cmd = "CALL GetPortsFromNuma(%s)'" % str(numa['id'])
-                        #self.cur.callproc('GetPortsFromNuma', (numa['id'],) )
-                        #every time a Procedure is launched you need to close and open the cursor 
-                        #under Error 2014: Commands out of sync; you can't run this command now
-                        #self.cur.close()   
-                        #self.cur = self.con.cursor(mdb.cursors.DictCursor)
-                        cmd="SELECT Mbps, pci, status, Mbps_used, instance_id, if(id=root_id,'PF','VF') as type_,\
-                             switch_port, switch_dpid, mac, source_name\
-                             FROM resources_port WHERE numa_id=%d ORDER BY root_id, type_ DESC" %  (numa['id'])
+                        # get ports
+                        # cmd = "CALL GetPortsFromNuma(%s)'" % str(numa['id'])
+                        # self.cur.callproc('GetPortsFromNuma', (numa['id'],) )
+                        # every time a Procedure is launched you need to close and open the cursor
+                        # under Error 2014: Commands out of sync; you can't run this command now
+                        # self.cur.close()
+                        # self.cur = self.con.cursor(mdb.cursors.DictCursor)
+                        cmd = "SELECT Mbps, pci, status, Mbps_used, instance_id, if(id=root_id,'PF','VF') as type_, "\
+                              "switch_port, switch_dpid, switch_mac, mac, source_name "\
+                              "FROM resources_port WHERE numa_id={} ORDER BY root_id, type_ DESC".format(numa['id'])
                         self.logger.debug(cmd)
                         self.cur.execute(cmd)
                         ifaces = self.cur.fetchall()
-                        #The SQL query will ensure to have SRIOV interfaces from a port first
+                        # The SQL query will ensure to have SRIOV interfaces from a port first
                         sriovs=[]
                         Mpbs_consumed = 0
                         numa['interfaces'] = []
@@ -533,6 +545,8 @@ class vim_db():
                                     del iface["switch_dpid"]
                                 if not iface["switch_port"]:
                                     del iface["switch_port"]
+                                if not iface["switch_mac"]:
+                                    del iface["switch_mac"]
                                 if sriovs:
                                     iface["sriovs"] = sriovs
                                 if Mpbs_consumed:
@@ -544,6 +558,7 @@ class vim_db():
                             else: #VF, SRIOV
                                 del iface["switch_port"]
                                 del iface["switch_dpid"]
+                                del iface["switch_mac"]
                                 del iface["type_"]
                                 del iface["Mbps"]
                                 sriovs.append(iface)
@@ -1046,8 +1061,8 @@ class vim_db():
                 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='{}'".format(instance_id)
+                    cmd = "SELECT uuid, name, description, progress, host_id, flavor_id, image_id, status, hypervisor, os_image_type, last_error, "\
+                        "tenant_id, ram, vcpus, created_at FROM instances WHERE uuid='{}'".format(instance_id) #Unikernels extension
                     self.logger.debug(cmd)
                     self.cur.execute(cmd)
                     if self.cur.rowcount == 0 : return 0, "instance '" + str(instance_id) +"'not found."
@@ -1064,7 +1079,7 @@ class vim_db():
                     #get extended
                     extended = {}
                     #get devices
-                    cmd = "SELECT type, vpci, image_id, xml,dev FROM instance_devices WHERE instance_id = '%s' " %  str(instance_id)
+                    cmd = "SELECT type, vpci, image_id, xml, dev, image_size FROM instance_devices WHERE instance_id = '%s' " %  str(instance_id)
                     self.logger.debug(cmd)
                     self.cur.execute(cmd)
                     if self.cur.rowcount > 0 :
@@ -1190,6 +1205,19 @@ class vim_db():
                         #self.logger.debug(error_text)
                         return -1, error_text
                     
+                    if not 'hypervisor' in requirements:        #Unikernels extension -END-
+                        requirements['hypervisor'] = "kvm"
+                    for valid_host in valid_hosts:
+                        if not 'hypervisors' in valid_host:
+                            valid_host['hypervisors'] = "kvm"
+
+                    valid_hosts = tuple(valid_host for valid_host in valid_hosts if requirements['hypervisor'] in valid_host['hypervisors'].split(","))
+
+                    if len(valid_hosts)<=0:
+                        error_text = 'No room at data center. Cannot find a host with %s hypervisor or not have enough resources available' % (str(requirements['hypervisor']))
+                        #self.logger.debug(error_text)
+                        return -1, error_text                   #Unikernels extension -END-
+
                     #elif req_numa != None:
                     #Find valid numa nodes for memory requirements
                     self.cur = self.con.cursor(mdb.cursors.DictCursor)
@@ -1420,8 +1448,18 @@ class vim_db():
                             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,
+                            if iface.get("ip_address"):
+                                if iface["ip_address"] in used_dhcp_ips:
+                                    iface["ip_address"] = None
+                            else:
+                                iface["ip_address"] = self.get_free_ip_from_range(dhcp_first_ip, dhcp_last_ip,
                                                                               dhcp_cidr, used_dhcp_ips)
+                            if 'links' in iface:
+                                del iface['links']
+                            if 'dns' in iface:
+                                del iface['dns']
+                            if 'routes' in iface:
+                                del iface['routes']
 
                         iface['uuid'] = str(myUuid.uuid1()) # create_uuid
                         cmd = "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface['uuid'], uuid)
@@ -1437,6 +1475,7 @@ class vim_db():
                         else:
                             iface['mac'] = iface['mac_address']
                             del iface['mac_address']
+
                         #iface['mac']=iface.pop('mac_address', None)  #for leaving mac generation to libvirt
                         keys    = ",".join(iface.keys())
                         values  = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", iface.values() ) )
@@ -1514,8 +1553,10 @@ class vim_db():
                             else:                    xml = 'Null'
                             if 'dev' in device: dev = "'" + device['dev'] + "'"
                             else:                    dev = 'Null'
-                            cmd = "INSERT INTO instance_devices (type, instance_id, image_id, vpci, xml, dev) VALUES ('%s','%s', %s, %s, %s, %s)" % \
-                                (device['type'], uuid, image_id, vpci, xml, dev)
+                            if 'image_size' in device: size = device['image_size']
+                            else:                    size = 0
+                            cmd = "INSERT INTO instance_devices (type, instance_id, image_id, vpci, xml, dev, image_size) VALUES ('%s','%s', %s, %s, %s, %s, %s)" % \
+                                (device['type'], uuid, image_id, vpci, xml, dev, str(size))
                             self.logger.debug(cmd)
                             self.cur.execute(cmd)
                     ##inserting new log
@@ -1538,15 +1579,16 @@ class vim_db():
         :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
+
+        ip_used_list.append(str(ips[1]))  # gw ip
+        ip_used_list.append(str(ips[-1]))  # broadcast ip
+        ip_used_list.append(first_ip)
+
         for vm_ip in ips:
-            if str(vm_ip) not in ip_used_list:
+            if str(vm_ip) not in ip_used_list and IPAddress(first_ip) <= IPAddress(vm_ip) <= IPAddress(last_ip):
                 return vm_ip
 
         return None