fix 1223. Increment ip address on scaling vdus
[osm/RO.git] / RO / osm_ro / nfvo.py
index 829697c..e346699 100644 (file)
@@ -490,9 +490,9 @@ def rollback(mydb,  vims, rollback_list):
                 logger.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item['what'], item["uuid"], str(e))
                 undeleted_items.append("{} '{}'".format(item['what'], item["uuid"]))
     if len(undeleted_items)==0:
-        return True,Rollback successful."
+        return True, "Rollback successful."
     else:
-        return False,Rollback fails to delete: " + str(undeleted_items)
+        return False, "Rollback fails to delete: " + str(undeleted_items)
 
 
 def check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1):
@@ -2971,6 +2971,7 @@ def unify_cloud_config(cloud_config_preserve, cloud_config):
 
 
 def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_id=None):
+    global plugins
     datacenter_id = None
     datacenter_name = None
     thread = None
@@ -2990,7 +2991,7 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i
             if datacenter_tenant_id:
                 where_["dt.uuid"] = datacenter_tenant_id
             datacenters = mydb.get_rows(
-                SELECT=("dt.uuid as datacenter_tenant_id, d.name as datacenter_name",),
+                SELECT=("dt.uuid as datacenter_tenant_id, d.name as datacenter_name", "d.type as type"),
                 FROM="datacenter_tenants as dt join tenants_datacenters as td on dt.uuid=td.datacenter_tenant_id "
                      "join datacenters as d on d.uuid=dt.datacenter_id",
                 WHERE=where_)
@@ -3001,6 +3002,10 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i
                 datacenter_name = datacenters[0]["datacenter_name"]
                 thread = vim_threads["running"].get(thread_id)
                 if not thread:
+                    datacenter_type = datacenters[0]["type"]
+                    plugin_name = "rovim_" + datacenter_type
+                    if plugin_name not in plugins:
+                        _load_plugin(plugin_name, type="vim")
                     thread_name = get_non_used_vim_name(datacenter_name, datacenter_id)
                     thread = vim_thread(task_lock, plugins, thread_name, None,
                                         thread_id, db=mydb)
@@ -3026,13 +3031,14 @@ def get_datacenter_uuid(mydb, tenant_id, datacenter_id_name):
                " dt on td.datacenter_tenant_id=dt.uuid"
     else:
         from_ = 'datacenters as d'
-    vimaccounts = mydb.get_rows(FROM=from_, SELECT=("d.uuid as uuid, d.name as name",), WHERE=WHERE_dict )
+    vimaccounts = mydb.get_rows(FROM=from_, SELECT=("d.uuid as uuid", "d.name as name", "d.type as type"),
+                                WHERE=WHERE_dict)
     if len(vimaccounts) == 0:
         raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), httperrors.Not_Found)
-    elif len(vimaccounts)>1:
-        #print "nfvo.datacenter_action() error. Several datacenters found"
+    elif len(vimaccounts) > 1:
+        # print "nfvo.datacenter_action() error. Several datacenters found"
         raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict)
-    return vimaccounts[0]["uuid"], vimaccounts[0]["name"]
+    return vimaccounts[0]["uuid"], vimaccounts[0]
 
 
 def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None, **extra_filter):
@@ -3783,7 +3789,7 @@ def create_instance(mydb, tenant_id, instance_dict):
         returned_instance["action_id"] = instance_action_id
         return returned_instance
     except (NfvoException, vimconn.VimConnException, sdnconn.SdnConnectorError, db_base_Exception) as e:
-        message = rollback(mydb, myvims, rollbackList)
+        _, message = rollback(mydb, myvims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "database Exception"
         elif isinstance(e, vimconn.VimConnException):
@@ -3791,12 +3797,31 @@ def create_instance(mydb, tenant_id, instance_dict):
         elif isinstance(e, sdnconn.SdnConnectorError):
             error_text = "WIM Exception"
         else:
-            error_text = "Exception"
-        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
+            error_text = "Exception " + str(type(e).__name__)
+        error_text += " {}. {}".format(e, message)
         # logger.error("create_instance: %s", error_text)
         logger.exception(e)
         raise NfvoException(error_text, e.http_code)
 
+def increment_ip_mac(ip_mac, vm_index=1):
+    if not isinstance(ip_mac, str):
+        return ip_mac
+    try:
+        # try with ipv4 look for last dot
+        i = ip_mac.rfind(".")
+        if i > 0:
+            i += 1
+            return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
+        # try with ipv6 or mac look for last colon. Operate in hex
+        i = ip_mac.rfind(":")
+        if i > 0:
+            i += 1
+            # format in hex, len can be 2 for mac or 4 for ipv6
+            return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(ip_mac[:i], int(ip_mac[i:], 16) + vm_index)
+    except:
+        pass
+    return None
+
 
 def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
     default_datacenter_id = params["default_datacenter_id"]
@@ -4155,16 +4180,11 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             av_index = None
         for vm_index in range(0, vm.get('count', 1)):
             vm_name = myVMDict['name'] + "-" + str(vm_index+1)
+            vm_networks = deepcopy(myVMDict['networks'])
             task_params = (vm_name, myVMDict['description'], myVMDict.get('start', None),
-                           myVMDict['imageRef'], myVMDict['flavorRef'], myVMDict['networks'], cloud_config_vm,
+                           myVMDict['imageRef'], myVMDict['flavorRef'], vm_networks, cloud_config_vm,
                            myVMDict['disks'], av_index, vnf_availability_zones)
-            # put interface uuid back to scenario[vnfs][vms[[interfaces]
-            for net in myVMDict['networks']:
-                if "vim_id" in net:
-                    for iface in vm['interfaces']:
-                        if net["name"] == iface["internal_name"]:
-                            iface["vim_id"] = net["vim_id"]
-                            break
+
             vm_uuid = str(uuid4())
             uuid_list.append(vm_uuid)
             db_vm = {
@@ -4178,28 +4198,32 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             }
             db_instance_vms.append(db_vm)
 
-            iface_index = 0
-            for db_vm_iface in db_vm_ifaces:
+            # put interface uuid back to scenario[vnfs][vms[[interfaces]
+            for net in vm_networks:
+                if "vim_id" in net:
+                    for iface in vm['interfaces']:
+                        if net["name"] == iface["internal_name"]:
+                            iface["vim_id"] = net["vim_id"]
+                            break
+
+                if vm_index > 0:
+                    if net.get("ip_address"):
+                        net["ip_address"] = increment_ip_mac(net.get("ip_address"), vm_index)
+                    if net.get("mac_address"):
+                        net["mac_address"] = increment_ip_mac(net.get("mac_address"), vm_index)
+
+            for iface_index, db_vm_iface in enumerate(db_vm_ifaces):
                 iface_uuid = str(uuid4())
                 uuid_list.append(iface_uuid)
                 db_vm_iface_instance = {
                     "uuid": iface_uuid,
-                    "instance_vm_id": vm_uuid
+                    "instance_vm_id": vm_uuid,
+                    "ip_address": vm_networks[iface_index].get("ip_address"),
+                    "mac_address": vm_networks[iface_index].get("mac_address")
                 }
                 db_vm_iface_instance.update(db_vm_iface)
-                if db_vm_iface_instance.get("ip_address"):  # increment ip_address
-                    ip = db_vm_iface_instance.get("ip_address")
-                    try:
-                        i = ip.rfind(".")
-                        if i > 0:
-                            i += 1
-                            ip = ip[i:] + str(int(ip[:i]) + 1)
-                            db_vm_iface_instance["ip_address"] = ip
-                    except:
-                        db_vm_iface_instance["ip_address"] = None
                 db_instance_interfaces.append(db_vm_iface_instance)
-                myVMDict['networks'][iface_index]["uuid"] = iface_uuid
-                iface_index += 1
+                vm_networks[iface_index]["uuid"] = iface_uuid
 
             db_vim_action = {
                 "instance_action_id": instance_action_id,
@@ -4856,7 +4880,6 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                 # TODO do the same for flavor and image when available
                 task_depends_on = []
                 task_params = extra["params"]
-                task_params_networks = deepcopy(task_params[5])
                 for iface in task_params[5]:
                     if iface["net_id"].startswith("TASK-"):
                         if "." not in iface["net_id"]:
@@ -4866,8 +4889,6 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                                                                   iface["net_id"][5:])
                         else:
                             task_depends_on.append(iface["net_id"][5:])
-                    if "mac_address" in iface:
-                        del iface["mac_address"]
 
                 vm_ifaces_to_clone = mydb.get_rows(FROM="instance_interfaces", WHERE={"instance_vm_id": target_vm["uuid"]})
                 for index in range(0, vdu_count):
@@ -4910,15 +4931,10 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                         iface["uuid"] = iface2iface[iface["uuid"]]
                         # increment ip_address
                         if iface.get("ip_address"):
-                            try:
-                                ip = iface["ip_address"]
-                                i = ip.rfind(".")
-                                if i > 0:
-                                    i += 1
-                                    ip = ip[i:] + str(int(ip[:i]) + 1)
-                                    iface["ip_address"] = ip
-                            except:
-                                iface["ip_address"] = None
+                            iface["ip_address"] = increment_ip_mac(iface.get("ip_address"), index+1)
+                        if iface.get("mac_address"):
+                            iface["mac_address"] = increment_ip_mac(iface.get("mac_address"), index+1)
+
                     if vm_name:
                         task_params_copy[0] = vm_name
                     db_vim_action = {
@@ -5223,45 +5239,49 @@ def delete_datacenter(mydb, datacenter):
 
 def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None, vim_tenant=None, vim_tenant_name=None,
                        vim_username=None, vim_password=None, config=None):
+    global plugins
     # get datacenter info
     try:
         if not datacenter_id:
             if not vim_id:
                 raise NfvoException("You must provide 'vim_id", http_code=httperrors.Bad_Request)
             datacenter_id = vim_id
-        datacenter_id, datacenter_name = get_datacenter_uuid(mydb, None, datacenter_id)
+        datacenter_id, datacenter = get_datacenter_uuid(mydb, None, datacenter_id)
+        datacenter_name = datacenter["name"]
+        datacenter_type = datacenter["type"]
 
         create_vim_tenant = True if not vim_tenant and not vim_tenant_name else False
 
         # get nfvo_tenant info
         tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant)
-        if vim_tenant_name==None:
-            vim_tenant_name=tenant_dict['name']
+        if vim_tenant_name is None:
+            vim_tenant_name = tenant_dict['name']
 
-        tenants_datacenter_dict={"nfvo_tenant_id":tenant_dict['uuid'], "datacenter_id":datacenter_id }
+        tenants_datacenter_dict = {"nfvo_tenant_id": tenant_dict['uuid'], "datacenter_id": datacenter_id}
         # #check that this association does not exist before
         # tenants_datacenters = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
         # if len(tenants_datacenters)>0:
-        #     raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id, tenant_dict['uuid']), httperrors.Conflict)
+        #     raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(
+        #                         datacenter_id, tenant_dict['uuid']), httperrors.Conflict)
 
-        vim_tenant_id_exist_atdb=False
+        vim_tenant_id_exist_atdb = False
         if not create_vim_tenant:
             where_={"datacenter_id": datacenter_id}
-            if vim_tenant!=None:
+            if vim_tenant is not None:
                 where_["vim_tenant_id"] = vim_tenant
-            if vim_tenant_name!=None:
+            if vim_tenant_name is not None:
                 where_["vim_tenant_name"] = vim_tenant_name
-            #check if vim_tenant_id is already at database
+            # check if vim_tenant_id is already at database
             datacenter_tenants_dict = mydb.get_rows(FROM='datacenter_tenants', WHERE=where_)
-            if len(datacenter_tenants_dict)>=1:
+            if len(datacenter_tenants_dict) >= 1:
                 datacenter_tenants_dict = datacenter_tenants_dict[0]
-                vim_tenant_id_exist_atdb=True
-                #TODO check if a field has changed and edit entry at datacenter_tenants at DB
-            else: #result=0
+                vim_tenant_id_exist_atdb = True
+                # TODO check if a field has changed and edit entry at datacenter_tenants at DB
+            else:  # result=0
                 datacenter_tenants_dict = {}
-                #insert at table datacenter_tenants
-        else: #if vim_tenant==None:
-            #create tenant at VIM if not provided
+                # insert at table datacenter_tenants
+        else:  # if vim_tenant==None:
+            # create tenant at VIM if not provided
             try:
                 _, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter_id, vim_user=vim_username,
                                                        vim_passwd=vim_password)
@@ -5270,10 +5290,9 @@ def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None,
             except vimconn.VimConnException as e:
                 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_name, e),
                                     httperrors.Internal_Server_Error)
-            datacenter_tenants_dict = {}
-            datacenter_tenants_dict["created"]="true"
+            datacenter_tenants_dict = {"created": "true"}
 
-        #fill datacenter_tenants table
+        # fill datacenter_tenants table
         if not vim_tenant_id_exist_atdb:
             datacenter_tenants_dict["vim_tenant_id"] = vim_tenant
             datacenter_tenants_dict["vim_tenant_name"] = vim_tenant_name
@@ -5289,12 +5308,15 @@ def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None,
             id_ = mydb.new_row('datacenter_tenants', datacenter_tenants_dict, add_uuid=True, confidential_data=True)
             datacenter_tenants_dict["uuid"] = id_
 
-        #fill tenants_datacenters table
+        # fill tenants_datacenters table
         datacenter_tenant_id = datacenter_tenants_dict["uuid"]
         tenants_datacenter_dict["datacenter_tenant_id"] = datacenter_tenant_id
         mydb.new_row('tenants_datacenters', tenants_datacenter_dict)
 
-        # create thread
+        # load plugin and create thread
+        plugin_name = "rovim_" + datacenter_type
+        if plugin_name not in plugins:
+            _load_plugin(plugin_name, type="vim")
         thread_name = get_non_used_vim_name(datacenter_name, datacenter_id)
         new_thread = vim_thread(task_lock, plugins, thread_name, None, datacenter_tenant_id, db=db)
         new_thread.start()