Fix Bug 2258 Setting vim_status as ACTIVE if an operation is successful.
[osm/RO.git] / NG-RO / osm_ng_ro / ns_thread.py
index 80f911d..861ed3d 100644 (file)
@@ -17,7 +17,7 @@
 #
 ##
 
-""""
+"""
 This is thread that interacts with a VIM. It processes TASKs sequentially against a single VIM.
 The tasks are stored at database in table ro_tasks
 A single ro_task refers to a VIM element (flavor, image, network, ...).
@@ -56,7 +56,7 @@ def deep_get(target_dict, *args, **kwargs):
     :param target_dict: dictionary to be read
     :param args: list of keys to read from  target_dict
     :param kwargs: only can contain default=value to return if key is not present in the nested dictionary
-    :return: The wanted value if exist, None or default otherwise
+    :return: The wanted value if exists, None or default otherwise
     """
     for key in args:
         if not isinstance(target_dict, dict) or key not in target_dict:
@@ -345,9 +345,7 @@ class VimInteractionVdu(VimInteractionBase):
         task = ro_task["tasks"][task_index]
         task_id = task["task_id"]
         created = False
-        created_items = {}
         target_vim = self.my_vims[ro_task["target_id"]]
-
         try:
             created = True
             params = task["params"]
@@ -389,7 +387,6 @@ class VimInteractionVdu(VimInteractionBase):
                         )
 
                     affinity_group["affinity_group_id"] = affinity_group_id
-
             vim_vm_id, created_items = target_vim.new_vminstance(**params_copy)
             interfaces = [iface["vim_id"] for iface in params_copy["net_list"]]
 
@@ -645,6 +642,7 @@ class VimInteractionImage(VimInteractionBase):
 
         try:
             # FIND
+            vim_image_id = ""
             if task.get("find_params"):
                 vim_images = target_vim.get_image_list(**task["find_params"])
 
@@ -665,7 +663,7 @@ class VimInteractionImage(VimInteractionBase):
 
             ro_vim_item_update = {
                 "vim_id": vim_image_id,
-                "vim_status": "DONE",
+                "vim_status": "ACTIVE",
                 "created": created,
                 "created_items": created_items,
                 "vim_details": None,
@@ -691,6 +689,112 @@ class VimInteractionImage(VimInteractionBase):
             return "FAILED", ro_vim_item_update
 
 
+class VimInteractionSharedVolume(VimInteractionBase):
+    def delete(self, ro_task, task_index):
+        task = ro_task["tasks"][task_index]
+        task_id = task["task_id"]
+        shared_volume_vim_id = ro_task["vim_info"]["vim_id"]
+        created_items = ro_task["vim_info"]["created_items"]
+        ro_vim_item_update_ok = {
+            "vim_status": "DELETED",
+            "created": False,
+            "vim_message": "DELETED",
+            "vim_id": None,
+        }
+        if created_items and created_items.get(shared_volume_vim_id).get("keep"):
+            ro_vim_item_update_ok = {
+                "vim_status": "ACTIVE",
+                "created": False,
+                "vim_message": None,
+            }
+            return "DONE", ro_vim_item_update_ok
+        try:
+            if shared_volume_vim_id:
+                target_vim = self.my_vims[ro_task["target_id"]]
+                target_vim.delete_shared_volumes(shared_volume_vim_id)
+        except vimconn.VimConnNotFoundException:
+            ro_vim_item_update_ok["vim_message"] = "already deleted"
+        except vimconn.VimConnException as e:
+            self.logger.error(
+                "ro_task={} vim={} del-shared-volume={}: {}".format(
+                    ro_task["_id"], ro_task["target_id"], shared_volume_vim_id, e
+                )
+            )
+            ro_vim_item_update = {
+                "vim_status": "VIM_ERROR",
+                "vim_message": "Error while deleting: {}".format(e),
+            }
+
+            return "FAILED", ro_vim_item_update
+
+        self.logger.debug(
+            "task={} {} del-shared-volume={} {}".format(
+                task_id,
+                ro_task["target_id"],
+                shared_volume_vim_id,
+                ro_vim_item_update_ok.get("vim_message", ""),
+            )
+        )
+
+        return "DONE", ro_vim_item_update_ok
+
+    def new(self, ro_task, task_index, task_depends):
+        task = ro_task["tasks"][task_index]
+        task_id = task["task_id"]
+        created = False
+        created_items = {}
+        target_vim = self.my_vims[ro_task["target_id"]]
+
+        try:
+            shared_volume_vim_id = None
+            shared_volume_data = None
+
+            if task.get("params"):
+                shared_volume_data = task["params"]
+
+            if shared_volume_data:
+                self.logger.info(
+                    f"Creating the new shared_volume for {shared_volume_data}\n"
+                )
+                (
+                    shared_volume_name,
+                    shared_volume_vim_id,
+                ) = target_vim.new_shared_volumes(shared_volume_data)
+                created = True
+                created_items[shared_volume_vim_id] = {
+                    "name": shared_volume_name,
+                    "keep": shared_volume_data.get("keep"),
+                }
+
+            ro_vim_item_update = {
+                "vim_id": shared_volume_vim_id,
+                "vim_status": "ACTIVE",
+                "created": created,
+                "created_items": created_items,
+                "vim_details": None,
+                "vim_message": None,
+            }
+            self.logger.debug(
+                "task={} {} new-shared-volume={} created={}".format(
+                    task_id, ro_task["target_id"], shared_volume_vim_id, created
+                )
+            )
+
+            return "DONE", ro_vim_item_update
+        except (vimconn.VimConnException, NsWorkerException) as e:
+            self.logger.error(
+                "task={} vim={} new-shared-volume:"
+                " {}".format(task_id, ro_task["target_id"], e)
+            )
+            ro_vim_item_update = {
+                "vim_status": "VIM_ERROR",
+                "created": created,
+                "vim_message": str(e),
+            }
+
+            return "FAILED", ro_vim_item_update
+
+
 class VimInteractionFlavor(VimInteractionBase):
     def delete(self, ro_task, task_index):
         task = ro_task["tasks"][task_index]
@@ -739,7 +843,6 @@ class VimInteractionFlavor(VimInteractionBase):
         created = False
         created_items = {}
         target_vim = self.my_vims[ro_task["target_id"]]
-
         try:
             # FIND
             vim_flavor_id = None
@@ -761,7 +864,7 @@ class VimInteractionFlavor(VimInteractionBase):
 
             ro_vim_item_update = {
                 "vim_id": vim_flavor_id,
-                "vim_status": "DONE",
+                "vim_status": "ACTIVE",
                 "created": created,
                 "created_items": created_items,
                 "vim_details": None,
@@ -839,6 +942,7 @@ class VimInteractionAffinityGroup(VimInteractionBase):
         try:
             affinity_group_vim_id = None
             affinity_group_data = None
+            param_affinity_group_id = ""
 
             if task.get("params"):
                 affinity_group_data = task["params"].get("affinity_group_data")
@@ -867,7 +971,7 @@ class VimInteractionAffinityGroup(VimInteractionBase):
 
             ro_vim_item_update = {
                 "vim_id": affinity_group_vim_id,
-                "vim_status": "DONE",
+                "vim_status": "ACTIVE",
                 "created": created,
                 "created_items": created_items,
                 "vim_details": None,
@@ -904,6 +1008,7 @@ class VimInteractionUpdateVdu(VimInteractionBase):
         target_vim = self.my_vims[ro_task["target_id"]]
 
         try:
+            vim_vm_id = ""
             if task.get("params"):
                 vim_vm_id = task["params"].get("vim_vm_id")
                 action = task["params"].get("action")
@@ -912,7 +1017,7 @@ class VimInteractionUpdateVdu(VimInteractionBase):
                 # created = True
             ro_vim_item_update = {
                 "vim_id": vim_vm_id,
-                "vim_status": "DONE",
+                "vim_status": "ACTIVE",
                 "created": created,
                 "created_items": created_items,
                 "vim_details": None,
@@ -940,8 +1045,8 @@ class VimInteractionSdnNet(VimInteractionBase):
     @staticmethod
     def _match_pci(port_pci, mapping):
         """
-        Check if port_pci matches with mapping
-        mapping can have brackets to indicate that several chars are accepted. e.g
+        Check if port_pci matches with mapping.
+        The mapping can have brackets to indicate that several chars are accepted. e.g
         pci '0000:af:10.1' matches with '0000:af:1[01].[1357]'
         :param port_pci: text
         :param mapping: text, can contain brackets to indicate several chars are available
@@ -1040,7 +1145,6 @@ class VimInteractionSdnNet(VimInteractionBase):
         return self.new(ro_task, task_create_index, None)
 
     def new(self, ro_task, task_index, task_depends):
-
         task = ro_task["tasks"][task_index]
         task_id = task["task_id"]
         target_vim = self.my_vims[ro_task["target_id"]]
@@ -1057,6 +1161,7 @@ class VimInteractionSdnNet(VimInteractionBase):
 
         try:
             # CREATE
+            db_vim = {}
             params = task["params"]
             vlds_to_connect = params.get("vlds", [])
             associated_vim = params.get("target_vim")
@@ -1344,6 +1449,7 @@ class VimInteractionMigration(VimInteractionBase):
         refreshed_vim_info = {}
 
         try:
+            vim_vm_id = ""
             if task.get("params"):
                 vim_vm_id = task["params"].get("vim_vm_id")
                 migrate_host = task["params"].get("migrate_host")
@@ -1425,6 +1531,7 @@ class VimInteractionResize(VimInteractionBase):
         target_vim = self.my_vims[ro_task["target_id"]]
 
         try:
+            vim_vm_id = ""
             if task.get("params"):
                 vim_vm_id = task["params"].get("vim_vm_id")
                 flavor_dict = task["params"].get("flavor_dict")
@@ -1452,7 +1559,7 @@ class VimInteractionResize(VimInteractionBase):
 
             ro_vim_item_update = {
                 "vim_id": vim_vm_id,
-                "vim_status": "DONE",
+                "vim_status": "ACTIVE",
                 "created": created,
                 "created_items": created_items,
                 "vim_details": None,
@@ -1541,6 +1648,9 @@ class NsWorker(threading.Thread):
         self.db = db
         self.item2class = {
             "net": VimInteractionNet(self.db, self.my_vims, self.db_vims, self.logger),
+            "shared-volumes": VimInteractionSharedVolume(
+                self.db, self.my_vims, self.db_vims, self.logger
+            ),
             "vdu": VimInteractionVdu(self.db, self.my_vims, self.db_vims, self.logger),
             "image": VimInteractionImage(
                 self.db, self.my_vims, self.db_vims, self.logger
@@ -1682,6 +1792,7 @@ class NsWorker(threading.Thread):
             if target == "wim"
             else "sdns"
         )
+        error_text = ""
 
         try:
             step = "Getting {} from db".format(target_id)
@@ -1776,7 +1887,7 @@ class NsWorker(threading.Thread):
         """
         Load or reload a vim_account, sdn_controller or wim_account.
         Read content from database, load the plugin if not loaded.
-        In case of error loading the plugin, it load a failing VIM_connector
+        In case of error loading the plugin, it loads a failing VIM_connector
         It fills self db_vims dictionary, my_vims dictionary and vim_targets list
         :param target_id: Contains type:_id; where type can be 'vim', ...
         :return: None if ok, descriptive text if error
@@ -2002,7 +2113,6 @@ class NsWorker(threading.Thread):
         """
         my_task = ro_task["tasks"][task_index]
         task_id = my_task["task_id"]
-        task_status = None
 
         if my_task["status"] == "FAILED":
             return None, None  # TODO need to be retry??
@@ -2090,18 +2200,15 @@ class NsWorker(threading.Thread):
                         return ro_task_dependency, task_index
         raise NsWorkerException("Cannot get depending task {}".format(task_id))
 
-    def update_vm_refresh(self):
+    def update_vm_refresh(self, ro_task):
         """Enables the VM status updates if self.refresh_config.active parameter
-        is not -1 and than updates the DB accordingly
+        is not -1 and then updates the DB accordingly
 
         """
         try:
             self.logger.debug("Checking if VM status update config")
             next_refresh = time.time()
-            if self.refresh_config.active == -1:
-                next_refresh = -1
-            else:
-                next_refresh += self.refresh_config.active
+            next_refresh = self._get_next_refresh(ro_task, next_refresh)
 
             if next_refresh != -1:
                 db_ro_task_update = {}
@@ -2136,6 +2243,23 @@ class NsWorker(threading.Thread):
         except Exception as e:
             self.logger.error(f"Error updating tasks to enable VM status updates: {e}")
 
+    def _get_next_refresh(self, ro_task: dict, next_refresh: float):
+        """Decide the next_refresh according to vim type and refresh config period.
+        Args:
+            ro_task (dict):             ro_task details
+            next_refresh    (float):    next refresh time as epoch format
+
+        Returns:
+            next_refresh    (float)     -1 if vm updates are disabled or vim type is openstack.
+        """
+        target_vim = ro_task["target_id"]
+        vim_type = self.db_vims[target_vim]["vim_type"]
+        if self.refresh_config.active == -1 or vim_type == "openstack":
+            next_refresh = -1
+        else:
+            next_refresh += self.refresh_config.active
+        return next_refresh
+
     def _process_pending_tasks(self, ro_task):
         ro_task_id = ro_task["_id"]
         now = time.time()
@@ -2157,10 +2281,7 @@ class NsWorker(threading.Thread):
             elif new_status == "BUILD":
                 next_refresh += self.refresh_config.build
             elif new_status == "DONE":
-                if self.refresh_config.active == -1:
-                    next_refresh = -1
-                else:
-                    next_refresh += self.refresh_config.active
+                next_refresh = self._get_next_refresh(ro_task, next_refresh)
             else:
                 next_refresh += self.refresh_config.error
 
@@ -2175,7 +2296,7 @@ class NsWorker(threading.Thread):
                 self._log_ro_task(ro_task, None, None, "TASK_WF", "GET_TASK")
             """
             # Check if vim status refresh is enabled again
-            self.update_vm_refresh()
+            self.update_vm_refresh(ro_task)
             # 0: get task_status_create
             lock_object = None
             task_status_create = None
@@ -2221,6 +2342,7 @@ class NsWorker(threading.Thread):
                     task_path = "tasks.{}.status".format(task_index)
                     try:
                         db_vim_info_update = None
+                        dependency_ro_task = {}
 
                         if task["status"] == "SCHEDULED":
                             # check if tasks that this depends on have been completed
@@ -2291,9 +2413,11 @@ class NsWorker(threading.Thread):
                             lock_object = LockRenew.add_lock_object(
                                 "ro_tasks", ro_task, self
                             )
-
                         if task["action"] == "DELETE":
-                            (new_status, db_vim_info_update,) = self._delete_task(
+                            (
+                                new_status,
+                                db_vim_info_update,
+                            ) = self._delete_task(
                                 ro_task, task_index, task_depends, db_ro_task_update
                             )
                             new_status = (
@@ -2336,12 +2460,14 @@ class NsWorker(threading.Thread):
                                     new_status, db_vim_info_update = self.item2class[
                                         task["item"]
                                     ].new(ro_task, task_index, task_depends)
-                                    # self._create_task(ro_task, task_index, task_depends, db_ro_task_update)
                                     _update_refresh(new_status)
                             else:
                                 refresh_at = ro_task["vim_info"]["refresh_at"]
                                 if refresh_at and refresh_at != -1 and now > refresh_at:
-                                    (new_status, db_vim_info_update,) = self.item2class[
+                                    (
+                                        new_status,
+                                        db_vim_info_update,
+                                    ) = self.item2class[
                                         task["item"]
                                     ].refresh(ro_task)
                                     _update_refresh(new_status)
@@ -2417,7 +2543,7 @@ class NsWorker(threading.Thread):
                     lock_object["locked_at"],
                     lock_object["locked_at"] + self.task_locked_time,
                 ]
-                # locked_at contains two times to avoid race condition. In case the lock has been renew, it will
+                # locked_at contains two times to avoid race condition. In case the lock has been renewed, it will
                 # contain exactly locked_at + self.task_locked_time
                 LockRenew.remove_lock_object(lock_object)
 
@@ -2429,7 +2555,7 @@ class NsWorker(threading.Thread):
             # modify own task. Try filtering by to_next_check. For race condition if to_check_at has been modified,
             # outside this task (by ro_nbi) do not update it
             db_ro_task_update["locked_by"] = None
-            # locked_at converted to int only for debugging. When has not decimals it means it has been unlocked
+            # locked_at converted to int only for debugging. When it is not decimals it means it has been unlocked
             db_ro_task_update["locked_at"] = int(now - self.task_locked_time)
             db_ro_task_update["modified_at"] = now
             db_ro_task_update["to_check_at"] = next_check_at