Fix Bug 2158 and Bug 2254 by arranging exception handling 47/13747/7
authorgatici <gulsum.atici@canonical.com>
Tue, 25 Jul 2023 21:34:04 +0000 (00:34 +0300)
committeraticig <gulsum.atici@canonical.com>
Thu, 10 Aug 2023 08:26:25 +0000 (10:26 +0200)
Change-Id: Id84e57944258536735eb114d4c77f471d700e1aa
Signed-off-by: gatici <gulsum.atici@canonical.com>
NG-RO/osm_ng_ro/ns_thread.py
RO-VIM-openstack/osm_rovim_openstack/tests/test_vimconn_openstack.py
RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py
releasenotes/notes/fix_bug_2158_2254-86a20d2b2a6ca5a9.yaml [new file with mode: 0644]

index 42a8a59..e64db28 100644 (file)
@@ -644,7 +644,9 @@ class VimInteractionImage(VimInteractionBase):
             # FIND
             vim_image_id = ""
             if task.get("find_params"):
-                vim_images = target_vim.get_image_list(**task["find_params"])
+                vim_images = target_vim.get_image_list(
+                    task["find_params"].get("filter_dict", {})
+                )
 
                 if not vim_images:
                     raise NsWorkerExceptionNotFound(
index a3da330..c287493 100644 (file)
@@ -27,15 +27,19 @@ from copy import deepcopy
 import logging
 import unittest
 
+import cinderclient.exceptions as cExceptions
 from mock import MagicMock, patch
+from neutronclient.common import exceptions as neExceptions
 from novaclient import exceptions as nvExceptions
 from novaclient.exceptions import ClientException, Conflict
 from osm_ro_plugin.vimconn import (
     VimConnConnectionException,
     VimConnException,
     VimConnNotFoundException,
+    VimConnUnexpectedResponse,
 )
 from osm_rovim_openstack.vimconn_openstack import vimconnector
+from requests.exceptions import ConnectionError
 
 __author__ = "Igor D.C."
 __date__ = "$23-aug-2017 23:59:59$"
@@ -1627,17 +1631,18 @@ class TestNewVmInstance(unittest.TestCase):
     @patch.object(vimconnector, "update_block_device_mapping")
     def test_new_shared_volumes(self, mock_update_block_device_mapping):
         """Create shared volume."""
-        self.vimconn.cinder = CopyingMock()
-        self.vimconn.cinder.volumes.create.return_value.id = volume_id4
-        shared_volume_data = {"size": 10, "name": "shared-volume"}
-        self.vimconn.cinder.volumes.create.side_effect = [
-            Volume("avaible", "multiattach", "shared-volume", volume_id4)
-        ]
+
+        class MyVolume:
+            name = "my-shared-volume"
+            id = volume_id4
+
+        self.vimconn.cinder.volumes.create.return_value = MyVolume()
+        shared_volume_data = {"size": 10, "name": "my-shared-volume"}
         result = self.vimconn.new_shared_volumes(shared_volume_data)
         self.vimconn.cinder.volumes.create.assert_called_once_with(
-            size=10, name="shared-volume", volume_type="multiattach"
+            size=10, name="my-shared-volume", volume_type="multiattach"
         )
-        self.assertEqual(result[0], "shared-volume")
+        self.assertEqual(result[0], "my-shared-volume")
         self.assertEqual(result[1], volume_id4)
 
     @patch.object(vimconnector, "update_block_device_mapping")
@@ -3894,7 +3899,9 @@ class TestNewVmInstance(unittest.TestCase):
             },
         )
 
-    def test_delete_floating_ip_by_id_floating_ip_raises_nvexception(self):
+    def test_delete_floating_ip_by_id__delete_floating_ip_raises_client_exception__operation_is_successful(
+        self,
+    ):
         """netron delete floating ip raises nvExceptions.ClientException."""
         created_items = {
             f"floating_ip:{floating_network_vim_id}": True,
@@ -3918,7 +3925,36 @@ class TestNewVmInstance(unittest.TestCase):
             "Error deleting floating ip: ClientException: Unknown Error (HTTP Client exception occurred.)"
         )
 
-    def test_delete_floating_ip_by_id_floating_ip_raises_vimconnexception(self):
+    def test_delete_floating_ip_by_id__delete_floating_ip_raises_connection_error__operation_fails(
+        self,
+    ):
+        """netron delete floating ip raises nvExceptions.ClientException."""
+        created_items = {
+            f"floating_ip:{floating_network_vim_id}": True,
+            f"port:{port_id}": True,
+        }
+        k_id = floating_network_vim_id
+        k = f"floating_ip:{floating_network_vim_id}"
+        self.vimconn.neutron.delete_floatingip.side_effect = ConnectionError(
+            "Connection exception occurred."
+        )
+        with self.assertRaises(VimConnConnectionException):
+            self.vimconn._delete_floating_ip_by_id(k, k_id, created_items)
+        self.vimconn.neutron.delete_floatingip.assert_called_once_with(k_id)
+        self.assertEqual(
+            created_items,
+            {
+                f"floating_ip:{floating_network_vim_id}": True,
+                f"port:{port_id}": True,
+            },
+        )
+        self.vimconn.logger.error.assert_called_once_with(
+            "Error deleting floating ip: ConnectionError: Connection exception occurred."
+        )
+
+    def test_delete_floating_ip_by_id_floating_ip_raises_vimconn_not_found_exception__operation_is_successful(
+        self,
+    ):
         """netron delete floating ip raises VimConnNotFoundException."""
         created_items = {
             f"floating_ip:{floating_network_vim_id}": True,
@@ -4053,7 +4089,9 @@ class TestNewVmInstance(unittest.TestCase):
         )
         self.assertEqual(created_items, expected_created_items)
 
-    def test_delete_volumes_by_id_with_cinder_delete_volume_raise_exception(self):
+    def test_delete_volumes_by_id_with_cinder__delete_volume_raise_client_exception__exception_is_not_raised(
+        self,
+    ):
         """cinder delete volume raises exception."""
         created_items = {
             f"floating_ip:{floating_network_vim_id}": True,
@@ -4071,8 +4109,8 @@ class TestNewVmInstance(unittest.TestCase):
         k = f"volume:{volume_id}"
         k_id = volume_id
         self.vimconn.cinder.volumes.get.return_value.status = "available"
-        self.vimconn.cinder.volumes.delete.side_effect = nvExceptions.ClientException(
-            "Connection aborted."
+        self.vimconn.cinder.volumes.delete.side_effect = cExceptions.ClientException(
+            403, "Connection aborted."
         )
         result = self.vimconn._delete_volumes_by_id_wth_cinder(
             k, k_id, volumes_to_hold, created_items
@@ -4081,7 +4119,42 @@ class TestNewVmInstance(unittest.TestCase):
         self.vimconn.cinder.volumes.get.assert_called_once_with(k_id)
         self.vimconn.cinder.volumes.delete.assert_called_once_with(k_id)
         self.vimconn.logger.error.assert_called_once_with(
-            "Error deleting volume: ClientException: Unknown Error (HTTP Connection aborted.)"
+            "Error deleting volume: ClientException: Connection aborted. (HTTP 403)"
+        )
+        self.assertEqual(created_items, expected_created_items)
+
+    def test_delete_volumes_by_id_with_cinder__delete_volume_raise_connection_exception__exception_is_raised(
+        self,
+    ):
+        """cinder delete volume raises exception."""
+        created_items = {
+            f"floating_ip:{floating_network_vim_id}": True,
+            f"volume:{volume_id2}": True,
+            f"volume:{volume_id}": True,
+            f"port:{port_id}": None,
+        }
+        expected_created_items = {
+            f"floating_ip:{floating_network_vim_id}": True,
+            f"volume:{volume_id2}": True,
+            f"volume:{volume_id}": True,
+            f"port:{port_id}": None,
+        }
+        volumes_to_hold = []
+        k = f"volume:{volume_id}"
+        k_id = volume_id
+        self.vimconn.cinder.volumes.get.return_value.status = "available"
+        self.vimconn.cinder.volumes.delete.side_effect = cExceptions.ConnectionError(
+            "Connection failed."
+        )
+        with self.assertRaises(VimConnConnectionException):
+            result = self.vimconn._delete_volumes_by_id_wth_cinder(
+                k, k_id, volumes_to_hold, created_items
+            )
+            self.assertEqual(result, None)
+        self.vimconn.cinder.volumes.get.assert_called_once_with(k_id)
+        self.vimconn.cinder.volumes.delete.assert_called_once_with(k_id)
+        self.vimconn.logger.error.assert_called_once_with(
+            "Error deleting volume: ConnectionError: Connection failed."
         )
         self.assertEqual(created_items, expected_created_items)
 
@@ -4105,7 +4178,7 @@ class TestNewVmInstance(unittest.TestCase):
         result = self.vimconn._delete_volumes_by_id_wth_cinder(
             k, k_id, volumes_to_hold, created_items
         )
-        self.assertEqual(result, None)
+        self.assertEqual(result, False)
         self.vimconn.cinder.volumes.get.assert_not_called()
         self.vimconn.cinder.volumes.delete.assert_not_called()
         self.vimconn.logger.error.assert_not_called()
@@ -4295,7 +4368,7 @@ class TestNewVmInstance(unittest.TestCase):
     @patch.object(vimconnector, "_get_item_name_id")
     @patch.object(vimconnector, "_delete_volumes_by_id_wth_cinder")
     @patch.object(vimconnector, "_delete_floating_ip_by_id")
-    def test_delete_created_items_delete_vol_raises(
+    def test_delete_created_items__delete_vol_raises_connection_error__operation_fails(
         self,
         mock_delete_floating_ip_by_id,
         mock_delete_volumes_by_id_wth_cinder,
@@ -4311,15 +4384,16 @@ class TestNewVmInstance(unittest.TestCase):
             ("floating_ip", f"{floating_network_vim_id}"),
             ("volume", f"{volume_id}"),
         ]
-        mock_delete_volumes_by_id_wth_cinder.side_effect = ConnectionError(
-            "Connection failed."
+        mock_delete_volumes_by_id_wth_cinder.side_effect = (
+            neExceptions.ConnectionFailed("Connection failed.")
         )
         volumes_to_hold = []
         keep_waiting = False
-        result = self.vimconn._delete_created_items(
-            created_items, volumes_to_hold, keep_waiting
-        )
-        self.assertEqual(result, False)
+        with self.assertRaises(VimConnConnectionException):
+            result = self.vimconn._delete_created_items(
+                created_items, volumes_to_hold, keep_waiting
+            )
+            self.assertEqual(result, None)
         self.assertEqual(mock_get_item_name_id.call_count, 2)
         mock_delete_volumes_by_id_wth_cinder.assert_called_once_with(
             f"volume:{volume_id}", f"{volume_id}", [], created_items
@@ -4336,7 +4410,7 @@ class TestNewVmInstance(unittest.TestCase):
     @patch.object(vimconnector, "_get_item_name_id")
     @patch.object(vimconnector, "_delete_volumes_by_id_wth_cinder")
     @patch.object(vimconnector, "_delete_floating_ip_by_id")
-    def test_delete_created_items_delete_fip_raises(
+    def test_delete_created_items__delete_fip_raises_connection_error__operation_fails(
         self,
         mock_delete_floating_ip_by_id,
         mock_delete_volumes_by_id_wth_cinder,
@@ -4358,14 +4432,13 @@ class TestNewVmInstance(unittest.TestCase):
         )
         volumes_to_hold = []
         keep_waiting = True
-        result = self.vimconn._delete_created_items(
-            created_items, volumes_to_hold, keep_waiting
-        )
-        self.assertEqual(result, True)
-        self.assertEqual(mock_get_item_name_id.call_count, 2)
-        mock_delete_volumes_by_id_wth_cinder.assert_called_once_with(
-            f"volume:{volume_id}", f"{volume_id}", [], created_items
-        )
+        with self.assertRaises(VimConnConnectionException):
+            result = self.vimconn._delete_created_items(
+                created_items, volumes_to_hold, keep_waiting
+            )
+            self.assertEqual(result, None)
+        self.assertEqual(mock_get_item_name_id.call_count, 1)
+        mock_delete_volumes_by_id_wth_cinder.assert_not_called()
         mock_delete_floating_ip_by_id.assert_called_once_with(
             f"floating_ip:{floating_network_vim_id}",
             f"{floating_network_vim_id}",
@@ -4378,7 +4451,7 @@ class TestNewVmInstance(unittest.TestCase):
     @patch.object(vimconnector, "_get_item_name_id")
     @patch.object(vimconnector, "_delete_volumes_by_id_wth_cinder")
     @patch.object(vimconnector, "_delete_floating_ip_by_id")
-    def test_delete_created_items_get_item_name_raises(
+    def test_delete_created_items_get_item_name_raises_type_error__operation_fails(
         self,
         mock_delete_floating_ip_by_id,
         mock_delete_volumes_by_id_wth_cinder,
@@ -4396,19 +4469,16 @@ class TestNewVmInstance(unittest.TestCase):
         ]
         volumes_to_hold = []
         keep_waiting = False
-        result = self.vimconn._delete_created_items(
-            created_items, volumes_to_hold, keep_waiting
-        )
-        self.assertEqual(result, False)
-        self.assertEqual(mock_get_item_name_id.call_count, 2)
+        with self.assertRaises(VimConnException):
+            result = self.vimconn._delete_created_items(
+                created_items, volumes_to_hold, keep_waiting
+            )
+            self.assertEqual(result, None)
+        self.assertEqual(mock_get_item_name_id.call_count, 1)
         mock_delete_volumes_by_id_wth_cinder.assert_not_called()
         mock_delete_floating_ip_by_id.assert_not_called()
         _call_logger = self.vimconn.logger.error.call_args_list
         self.assertEqual(_call_logger[0][0], ("Error deleting 3: Invalid Type",))
-        self.assertEqual(
-            _call_logger[1][0],
-            (f"Error deleting volume{volume_id}: Invalid attribute",),
-        )
 
     @patch.object(vimconnector, "_get_item_name_id")
     @patch.object(vimconnector, "_delete_volumes_by_id_wth_cinder")
@@ -4578,16 +4648,14 @@ class TestNewVmInstance(unittest.TestCase):
 
     @patch("time.sleep")
     @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items")
-    @patch.object(vimconnector, "_format_exception")
     @patch.object(vimconnector, "_reload_connection")
     @patch.object(vimconnector, "_delete_vm_ports_attached_to_network")
     @patch.object(vimconnector, "_delete_created_items")
-    def test_delete_vminstance_extract_items_wth_keep_raises(
+    def test_delete_vminstance__extract_items_wth_keep_raises_attributeerror__raise_vimconnexception(
         self,
         mock_delete_created_items,
         mock_delete_vm_ports_attached_to_network,
         mock_reload_connection,
-        mock_format_exception,
         mock_extract_items_wth_keep_flag_from_created_items,
         mock_sleep,
     ):
@@ -4603,7 +4671,7 @@ class TestNewVmInstance(unittest.TestCase):
         mock_extract_items_wth_keep_flag_from_created_items.side_effect = AttributeError
         volumes_to_hold = []
         mock_delete_created_items.return_value = False
-        with self.assertRaises(AttributeError):
+        with self.assertRaises(VimConnException):
             self.vimconn.delete_vminstance(
                 vm_id, initial_created_items, volumes_to_hold
             )
@@ -4612,7 +4680,6 @@ class TestNewVmInstance(unittest.TestCase):
         self.vimconn.nova.servers.delete.assert_not_called()
         mock_delete_created_items.assert_not_called()
         mock_sleep.assert_not_called()
-        mock_format_exception.assert_not_called()
         mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with(
             initial_created_items
         )
@@ -4623,7 +4690,7 @@ class TestNewVmInstance(unittest.TestCase):
     @patch.object(vimconnector, "_reload_connection")
     @patch.object(vimconnector, "_delete_vm_ports_attached_to_network")
     @patch.object(vimconnector, "_delete_created_items")
-    def test_delete_vminstance_delete_created_items_raises(
+    def test_delete_vminstance__delete_created_items_returns_true__delete_created_items_called_several_times(
         self,
         mock_delete_created_items,
         mock_delete_vm_ports_attached_to_network,
@@ -4638,15 +4705,12 @@ class TestNewVmInstance(unittest.TestCase):
         mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items
         mock_sleep = MagicMock()
         volumes_to_hold = []
-        err = ConnectionError("ClientException occurred.")
-        mock_delete_created_items.side_effect = err
-        with self.assertRaises(ConnectionError) as err:
-            self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold)
-            self.assertEqual(str(err), "ClientException occurred.")
+        mock_delete_created_items.side_effect = [True, False]
+        self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold)
         mock_reload_connection.assert_called_once()
         mock_delete_vm_ports_attached_to_network.assert_called_once_with(created_items)
         self.vimconn.nova.servers.delete.assert_called_once_with(vm_id)
-        mock_delete_created_items.assert_called_once()
+        self.assertEqual(mock_delete_created_items.call_count, 2)
         mock_sleep.assert_not_called()
         mock_extract_items_wth_keep_flag_from_created_items.assert_called_once_with(
             created_items
@@ -4654,16 +4718,14 @@ class TestNewVmInstance(unittest.TestCase):
 
     @patch("time.sleep")
     @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items")
-    @patch.object(vimconnector, "_format_exception")
     @patch.object(vimconnector, "_reload_connection")
     @patch.object(vimconnector, "_delete_vm_ports_attached_to_network")
     @patch.object(vimconnector, "_delete_created_items")
-    def test_delete_vminstance_delete_vm_ports_raises(
+    def test_delete_vminstance__delete_vm_ports_raises_connection_error__raise_vimconnconnectionexception(
         self,
         mock_delete_created_items,
         mock_delete_vm_ports_attached_to_network,
         mock_reload_connection,
-        mock_format_exception,
         mock_extract_items_wth_keep_flag_from_created_items,
         mock_sleep,
     ):
@@ -4674,10 +4736,9 @@ class TestNewVmInstance(unittest.TestCase):
         volumes_to_hold = [f"{volume_id}", f"{volume_id2}"]
         err = ConnectionError("ClientException occurred.")
         mock_delete_vm_ports_attached_to_network.side_effect = err
-        mock_delete_created_items.side_effect = err
-        with self.assertRaises(ConnectionError) as err:
+        mock_delete_created_items.return_value = False
+        with self.assertRaises(VimConnConnectionException):
             self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold)
-            self.assertEqual(str(err), "ClientException occurred.")
         mock_reload_connection.assert_called_once()
         mock_delete_vm_ports_attached_to_network.assert_called_once_with(created_items)
         self.vimconn.nova.servers.delete.assert_not_called()
@@ -4689,16 +4750,14 @@ class TestNewVmInstance(unittest.TestCase):
 
     @patch("time.sleep")
     @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items")
-    @patch.object(vimconnector, "_format_exception")
     @patch.object(vimconnector, "_reload_connection")
     @patch.object(vimconnector, "_delete_vm_ports_attached_to_network")
     @patch.object(vimconnector, "_delete_created_items")
-    def test_delete_vminstance_nova_server_delete_raises(
+    def test_delete_vminstance__nova_server_delete_raises_clientexception__raise_vimconn_unexpected_response(
         self,
         mock_delete_created_items,
         mock_delete_vm_ports_attached_to_network,
         mock_reload_connection,
-        mock_format_exception,
         mock_extract_items_wth_keep_flag_from_created_items,
         mock_sleep,
     ):
@@ -4707,12 +4766,11 @@ class TestNewVmInstance(unittest.TestCase):
         created_items = deepcopy(created_items_all_true)
         mock_extract_items_wth_keep_flag_from_created_items.return_value = created_items
         volumes_to_hold = [f"{volume_id}", f"{volume_id2}"]
-        err = VimConnConnectionException("ClientException occurred.")
+        err = nvExceptions.ClientException("ClientException occurred.")
         self.vimconn.nova.servers.delete.side_effect = err
         mock_delete_created_items.side_effect = err
-        with self.assertRaises(VimConnConnectionException) as err:
+        with self.assertRaises(VimConnUnexpectedResponse):
             self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold)
-            self.assertEqual(str(err), "ClientException occurred.")
         mock_reload_connection.assert_called_once()
         mock_delete_vm_ports_attached_to_network.assert_called_once_with(created_items)
         self.vimconn.nova.servers.delete.assert_called_once_with(vm_id)
@@ -4724,16 +4782,14 @@ class TestNewVmInstance(unittest.TestCase):
 
     @patch("time.sleep")
     @patch.object(vimconnector, "_extract_items_wth_keep_flag_from_created_items")
-    @patch.object(vimconnector, "_format_exception")
     @patch.object(vimconnector, "_reload_connection")
     @patch.object(vimconnector, "_delete_vm_ports_attached_to_network")
     @patch.object(vimconnector, "_delete_created_items")
-    def test_delete_vminstance_reload_connection_raises(
+    def test_delete_vminstance__reload_connection_raises_connection_error__raises_vimconnconnection_exception(
         self,
         mock_delete_created_items,
         mock_delete_vm_ports_attached_to_network,
         mock_reload_connection,
-        mock_format_exception,
         mock_extract_items_wth_keep_flag_from_created_items,
         mock_sleep,
     ):
@@ -4746,9 +4802,8 @@ class TestNewVmInstance(unittest.TestCase):
         err = ConnectionError("ClientException occurred.")
         mock_delete_created_items.return_value = False
         mock_reload_connection.side_effect = err
-        with self.assertRaises(ConnectionError) as err:
+        with self.assertRaises(VimConnConnectionException):
             self.vimconn.delete_vminstance(vm_id, created_items, volumes_to_hold)
-            self.assertEqual(str(err), "ClientException occurred.")
         mock_reload_connection.assert_called_once()
         mock_delete_vm_ports_attached_to_network.assert_not_called()
         self.vimconn.nova.servers.delete.assert_not_called()
index 9d47437..bca9479 100644 (file)
@@ -41,6 +41,7 @@ import time
 from typing import Dict, List, Optional, Tuple
 
 from cinderclient import client as cClient
+import cinderclient.exceptions as cExceptions
 from glanceclient import client as glClient
 import glanceclient.exc as gl1Exceptions
 from keystoneauth1 import session
@@ -85,6 +86,16 @@ volume_timeout = 1800
 server_timeout = 1800
 
 
+def catch_any_exception(func):
+    def format_exception(*args, **kwargs):
+        try:
+            return func(*args, *kwargs)
+        except Exception as e:
+            vimconnector._format_exception(e)
+
+    return format_exception
+
+
 class SafeDumper(yaml.SafeDumper):
     def represent_data(self, data):
         # Openstack APIs use custom subclasses of dict and YAML safe dumper
@@ -525,7 +536,8 @@ class vimconnector(vimconn.VimConnector):
         # Types. Also, abstract vimconnector should call the validation
         # method before the implemented VIM connectors are called.
 
-    def _format_exception(self, exception):
+    @staticmethod
+    def _format_exception(exception):
         """Transform a keystone, nova, neutron  exception into a vimconn exception discovering the cause"""
         message_error = str(exception)
         tip = ""
@@ -535,8 +547,10 @@ class vimconnector(vimconn.VimConnector):
             (
                 neExceptions.NetworkNotFoundClient,
                 nvExceptions.NotFound,
+                nvExceptions.ResourceNotFound,
                 ksExceptions.NotFound,
                 gl1Exceptions.HTTPNotFound,
+                cExceptions.NotFound,
             ),
         ):
             raise vimconn.VimConnNotFoundException(
@@ -551,6 +565,7 @@ class vimconnector(vimconn.VimConnector):
                 ConnectionError,
                 ksExceptions.ConnectionError,
                 neExceptions.ConnectionFailed,
+                cExceptions.ConnectionError,
             ),
         ):
             if type(exception).__name__ == "SSLError":
@@ -565,6 +580,8 @@ class vimconnector(vimconn.VimConnector):
                 KeyError,
                 nvExceptions.BadRequest,
                 ksExceptions.BadRequest,
+                gl1Exceptions.BadRequest,
+                cExceptions.BadRequest,
             ),
         ):
             if message_error == "OS-EXT-SRV-ATTR:host":
@@ -582,6 +599,7 @@ class vimconnector(vimconn.VimConnector):
                 nvExceptions.ClientException,
                 ksExceptions.ClientException,
                 neExceptions.NeutronException,
+                cExceptions.ClientException,
             ),
         ):
             raise vimconn.VimConnUnexpectedResponse(
@@ -594,9 +612,10 @@ class vimconnector(vimconn.VimConnector):
         elif isinstance(exception, vimconn.VimConnException):
             raise exception
         else:  # ()
-            self.logger.error("General Exception " + message_error, exc_info=True)
+            logger = logging.getLogger("ro.vim.openstack")
+            logger.error("General Exception " + message_error, exc_info=True)
 
-            raise vimconn.VimConnConnectionException(
+            raise vimconn.VimConnException(
                 type(exception).__name__ + ": " + message_error
             )
 
@@ -673,7 +692,6 @@ class vimconnector(vimconn.VimConnector):
         Returns the tenant list of dictionaries: [{'name':'<name>, 'id':'<id>, ...}, ...]
         """
         self.logger.debug("Getting tenants from VIM filter: '%s'", str(filter_dict))
-
         try:
             self._reload_connection()
 
@@ -703,7 +721,6 @@ class vimconnector(vimconn.VimConnector):
     def new_tenant(self, tenant_name, tenant_description):
         """Adds a new tenant to openstack VIM. Returns the tenant identifier"""
         self.logger.debug("Adding a new tenant name: %s", tenant_name)
-
         try:
             self._reload_connection()
 
@@ -729,7 +746,6 @@ class vimconnector(vimconn.VimConnector):
     def delete_tenant(self, tenant_id):
         """Delete a tenant from openstack VIM. Returns the old tenant identifier"""
         self.logger.debug("Deleting tenant %s from VIM", tenant_id)
-
         try:
             self._reload_connection()
 
@@ -739,6 +755,7 @@ class vimconnector(vimconn.VimConnector):
                 self.keystone.tenants.delete(tenant_id)
 
             return tenant_id
+
         except (
             ksExceptions.ConnectionError,
             ksExceptions.ClientException,
@@ -828,7 +845,7 @@ class vimconnector(vimconn.VimConnector):
                         "dataplane_physical_net"
                     )
 
-                    # if it is non empty list, use the first value. If it is a string use the value directly
+                    # if it is non-empty list, use the first value. If it is a string use the value directly
                     if (
                         isinstance(provider_physical_network, (tuple, list))
                         and provider_physical_network
@@ -1007,6 +1024,14 @@ class vimconnector(vimconn.VimConnector):
 
                     if k_item == "l2gwconn":
                         self.neutron.delete_l2_gateway_connection(k_id)
+
+                except (neExceptions.ConnectionFailed, ConnectionError) as e2:
+                    self.logger.error(
+                        "Error deleting l2 gateway connection: {}: {}".format(
+                            type(e2).__name__, e2
+                        )
+                    )
+                    self._format_exception(e2)
                 except Exception as e2:
                     self.logger.error(
                         "Error deleting l2 gateway connection: {}: {}".format(
@@ -1031,7 +1056,6 @@ class vimconnector(vimconn.VimConnector):
         Returns the network list of dictionaries
         """
         self.logger.debug("Getting network from VIM filter: '%s'", str(filter_dict))
-
         try:
             self._reload_connection()
             filter_dict_os = filter_dict.copy()
@@ -1091,6 +1115,7 @@ class vimconnector(vimconn.VimConnector):
 
         return net
 
+    @catch_any_exception
     def delete_network(self, net_id, created_items=None):
         """
         Removes a tenant network from VIM and its associated elements
@@ -1114,6 +1139,14 @@ class vimconnector(vimconn.VimConnector):
                     k_item, _, k_id = k.partition(":")
                     if k_item == "l2gwconn":
                         self.neutron.delete_l2_gateway_connection(k_id)
+
+                except (neExceptions.ConnectionFailed, ConnectionError) as e:
+                    self.logger.error(
+                        "Error deleting l2 gateway connection: {}: {}".format(
+                            type(e).__name__, e
+                        )
+                    )
+                    self._format_exception(e)
                 except Exception as e:
                     self.logger.error(
                         "Error deleting l2 gateway connection: {}: {}".format(
@@ -1126,21 +1159,22 @@ class vimconnector(vimconn.VimConnector):
             for p in ports["ports"]:
                 try:
                     self.neutron.delete_port(p["id"])
+
+                except (neExceptions.ConnectionFailed, ConnectionError) as e:
+                    self.logger.error("Error deleting port %s: %s", p["id"], str(e))
+                    # If there is connection error, it raises.
+                    self._format_exception(e)
                 except Exception as e:
                     self.logger.error("Error deleting port %s: %s", p["id"], str(e))
 
             self.neutron.delete_network(net_id)
 
             return net_id
-        except (
-            neExceptions.ConnectionFailed,
-            neExceptions.NetworkNotFoundClient,
-            neExceptions.NeutronException,
-            ksExceptions.ClientException,
-            neExceptions.NeutronException,
-            ConnectionError,
-        ) as e:
-            self._format_exception(e)
+        except (neExceptions.NetworkNotFoundClient, neExceptions.NotFound) as e:
+            # If network to be deleted is not found, it does not raise.
+            self.logger.warning(
+                f"Error deleting network: {net_id} is not found, {str(e)}"
+            )
 
     def refresh_nets_status(self, net_list):
         """Get the status of the networks
@@ -1193,13 +1227,11 @@ class vimconnector(vimconn.VimConnector):
     def get_flavor(self, flavor_id):
         """Obtain flavor details from the  VIM. Returns the flavor dict details"""
         self.logger.debug("Getting flavor '%s'", flavor_id)
-
         try:
             self._reload_connection()
             flavor = self.nova.flavors.find(id=flavor_id)
-            # TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema)
-
             return flavor.to_dict()
+
         except (
             nvExceptions.NotFound,
             nvExceptions.ClientException,
@@ -1271,6 +1303,7 @@ class vimconnector(vimconn.VimConnector):
             )
         except (
             nvExceptions.NotFound,
+            nvExceptions.BadRequest,
             nvExceptions.ClientException,
             ksExceptions.ClientException,
             ConnectionError,
@@ -1541,6 +1574,7 @@ class vimconnector(vimconn.VimConnector):
             flavor_data.get("extended"),
         )
 
+    @catch_any_exception
     def new_flavor(self, flavor_data: dict, change_name_if_used: bool = True) -> str:
         """Adds a tenant flavor to openstack VIM.
         if change_name_if_used is True, it will change name in case of conflict,
@@ -1558,70 +1592,58 @@ class vimconnector(vimconn.VimConnector):
         retry = 0
         max_retries = 3
         name_suffix = 0
+        name = flavor_data["name"]
+        while retry < max_retries:
+            retry += 1
+            try:
+                self._reload_connection()
 
-        try:
-            name = flavor_data["name"]
-            while retry < max_retries:
-                retry += 1
-                try:
-                    self._reload_connection()
+                if change_name_if_used:
+                    name = self._change_flavor_name(name, name_suffix, flavor_data)
 
-                    if change_name_if_used:
-                        name = self._change_flavor_name(name, name_suffix, flavor_data)
+                ram, vcpus, extra_specs, extended = self._get_flavor_details(
+                    flavor_data
+                )
+                if extended:
+                    self._process_extended_config_of_flavor(extended, extra_specs)
 
-                    ram, vcpus, extra_specs, extended = self._get_flavor_details(
-                        flavor_data
-                    )
-                    if extended:
-                        self._process_extended_config_of_flavor(extended, extra_specs)
-
-                    # Create flavor
-
-                    new_flavor = self.nova.flavors.create(
-                        name=name,
-                        ram=ram,
-                        vcpus=vcpus,
-                        disk=flavor_data.get("disk", 0),
-                        ephemeral=flavor_data.get("ephemeral", 0),
-                        swap=flavor_data.get("swap", 0),
-                        is_public=flavor_data.get("is_public", True),
-                    )
+                # Create flavor
 
-                    # Add metadata
-                    if extra_specs:
-                        new_flavor.set_keys(extra_specs)
+                new_flavor = self.nova.flavors.create(
+                    name=name,
+                    ram=ram,
+                    vcpus=vcpus,
+                    disk=flavor_data.get("disk", 0),
+                    ephemeral=flavor_data.get("ephemeral", 0),
+                    swap=flavor_data.get("swap", 0),
+                    is_public=flavor_data.get("is_public", True),
+                )
 
-                    return new_flavor.id
+                # Add metadata
+                if extra_specs:
+                    new_flavor.set_keys(extra_specs)
 
-                except nvExceptions.Conflict as e:
-                    if change_name_if_used and retry < max_retries:
-                        continue
+                return new_flavor.id
 
-                    self._format_exception(e)
+            except nvExceptions.Conflict as e:
+                if change_name_if_used and retry < max_retries:
+                    continue
 
-        except (
-            ksExceptions.ClientException,
-            nvExceptions.ClientException,
-            ConnectionError,
-            KeyError,
-        ) as e:
-            self._format_exception(e)
+                self._format_exception(e)
 
+    @catch_any_exception
     def delete_flavor(self, flavor_id):
         """Deletes a tenant flavor from openstack VIM. Returns the old flavor_id"""
         try:
             self._reload_connection()
             self.nova.flavors.delete(flavor_id)
-
             return flavor_id
-        # except nvExceptions.BadRequest as e:
-        except (
-            nvExceptions.NotFound,
-            ksExceptions.ClientException,
-            nvExceptions.ClientException,
-            ConnectionError,
-        ) as e:
-            self._format_exception(e)
+
+        except (nvExceptions.NotFound, nvExceptions.ResourceNotFound) as e:
+            # If flavor is not found, it does not raise.
+            self.logger.warning(
+                f"Error deleting flavor: {flavor_id} is not found, {str(e.message)}"
+            )
 
     def new_image(self, image_dict):
         """
@@ -1704,12 +1726,6 @@ class vimconnector(vimconn.VimConnector):
                 self.glance.images.update(new_image.id, **metadata_to_load)
 
                 return new_image.id
-            except (
-                nvExceptions.Conflict,
-                ksExceptions.ClientException,
-                nvExceptions.ClientException,
-            ) as e:
-                self._format_exception(e)
             except (
                 HTTPException,
                 gl1Exceptions.HTTPException,
@@ -1725,7 +1741,10 @@ class vimconnector(vimconn.VimConnector):
                     "{}: {} for {}".format(type(e).__name__, e, image_dict["location"]),
                     http_code=vimconn.HTTP_Bad_Request,
                 )
+            except Exception as e:
+                self._format_exception(e)
 
+    @catch_any_exception
     def delete_image(self, image_id):
         """Deletes a tenant image from openstack VIM. Returns the old id"""
         try:
@@ -1733,36 +1752,25 @@ class vimconnector(vimconn.VimConnector):
             self.glance.images.delete(image_id)
 
             return image_id
-        except (
-            nvExceptions.NotFound,
-            ksExceptions.ClientException,
-            nvExceptions.ClientException,
-            gl1Exceptions.CommunicationError,
-            gl1Exceptions.HTTPNotFound,
-            ConnectionError,
-        ) as e:  # TODO remove
-            self._format_exception(e)
+        except gl1Exceptions.NotFound as e:
+            # If image is not found, it does not raise.
+            self.logger.warning(
+                f"Error deleting image: {image_id} is not found, {str(e)}"
+            )
 
+    @catch_any_exception
     def get_image_id_from_path(self, path):
         """Get the image id from image path in the VIM database. Returns the image_id"""
-        try:
-            self._reload_connection()
-            images = self.glance.images.list()
+        self._reload_connection()
+        images = self.glance.images.list()
 
-            for image in images:
-                if image.metadata.get("location") == path:
-                    return image.id
+        for image in images:
+            if image.metadata.get("location") == path:
+                return image.id
 
-            raise vimconn.VimConnNotFoundException(
-                "image with location '{}' not found".format(path)
-            )
-        except (
-            ksExceptions.ClientException,
-            nvExceptions.ClientException,
-            gl1Exceptions.CommunicationError,
-            ConnectionError,
-        ) as e:
-            self._format_exception(e)
+        raise vimconn.VimConnNotFoundException(
+            "image with location '{}' not found".format(path)
+        )
 
     def get_image_list(self, filter_dict={}):
         """Obtain tenant images from VIM
@@ -1775,7 +1783,6 @@ class vimconnector(vimconn.VimConnector):
             List can be empty
         """
         self.logger.debug("Getting image list from VIM filter: '%s'", str(filter_dict))
-
         try:
             self._reload_connection()
             # filter_dict_os = filter_dict.copy()
@@ -1802,6 +1809,7 @@ class vimconnector(vimconn.VimConnector):
                     pass
 
             return filtered_list
+
         except (
             ksExceptions.ClientException,
             nvExceptions.ClientException,
@@ -2185,16 +2193,14 @@ class vimconnector(vimconn.VimConnector):
             volume_txt += ":keep"
         created_items[volume_txt] = True
 
+    @catch_any_exception
     def new_shared_volumes(self, shared_volume_data) -> (str, str):
-        try:
-            volume = self.cinder.volumes.create(
-                size=shared_volume_data["size"],
-                name=shared_volume_data["name"],
-                volume_type="multiattach",
-            )
-            return (volume.name, volume.id)
-        except (ConnectionError, KeyError) as e:
-            self._format_exception(e)
+        volume = self.cinder.volumes.create(
+            size=shared_volume_data["size"],
+            name=shared_volume_data["name"],
+            volume_type="multiattach",
+        )
+        return volume.name, volume.id
 
     def _prepare_shared_volumes(
         self,
@@ -2774,20 +2780,19 @@ class vimconnector(vimconn.VimConnector):
             flavor_id,
             str(net_list),
         )
+        server = None
+        created_items = {}
+        net_list_vim = []
+        # list of external networks to be connected to instance, later on used to create floating_ip
+        external_network = []
+        # List of ports with port-security disabled
+        no_secured_ports = []
+        block_device_mapping = {}
+        existing_vim_volumes = []
+        server_group_id = None
+        scheduller_hints = {}
 
         try:
-            server = None
-            created_items = {}
-            net_list_vim = []
-            # list of external networks to be connected to instance, later on used to create floating_ip
-            external_network = []
-            # List of ports with port-security disabled
-            no_secured_ports = []
-            block_device_mapping = {}
-            existing_vim_volumes = []
-            server_group_id = None
-            scheduller_hints = {}
-
             # Check the Openstack Connection
             self._reload_connection()
 
@@ -2907,6 +2912,7 @@ class vimconnector(vimconn.VimConnector):
         """Returns the VM instance information from VIM"""
         return self._find_nova_server(vm_id)
 
+    @catch_any_exception
     def get_vminstance_console(self, vm_id, console_type="vnc"):
         """
         Get a console for the virtual machine
@@ -2922,66 +2928,56 @@ class vimconnector(vimconn.VimConnector):
                 suffix:   extra text, e.g. the http path and query string
         """
         self.logger.debug("Getting VM CONSOLE from VIM")
+        self._reload_connection()
+        server = self.nova.servers.find(id=vm_id)
+
+        if console_type is None or console_type == "novnc":
+            console_dict = server.get_vnc_console("novnc")
+        elif console_type == "xvpvnc":
+            console_dict = server.get_vnc_console(console_type)
+        elif console_type == "rdp-html5":
+            console_dict = server.get_rdp_console(console_type)
+        elif console_type == "spice-html5":
+            console_dict = server.get_spice_console(console_type)
+        else:
+            raise vimconn.VimConnException(
+                "console type '{}' not allowed".format(console_type),
+                http_code=vimconn.HTTP_Bad_Request,
+            )
 
-        try:
-            self._reload_connection()
-            server = self.nova.servers.find(id=vm_id)
+        console_dict1 = console_dict.get("console")
 
-            if console_type is None or console_type == "novnc":
-                console_dict = server.get_vnc_console("novnc")
-            elif console_type == "xvpvnc":
-                console_dict = server.get_vnc_console(console_type)
-            elif console_type == "rdp-html5":
-                console_dict = server.get_rdp_console(console_type)
-            elif console_type == "spice-html5":
-                console_dict = server.get_spice_console(console_type)
-            else:
-                raise vimconn.VimConnException(
-                    "console type '{}' not allowed".format(console_type),
-                    http_code=vimconn.HTTP_Bad_Request,
-                )
-
-            console_dict1 = console_dict.get("console")
+        if console_dict1:
+            console_url = console_dict1.get("url")
 
-            if console_dict1:
-                console_url = console_dict1.get("url")
+            if console_url:
+                # parse console_url
+                protocol_index = console_url.find("//")
+                suffix_index = (
+                    console_url[protocol_index + 2 :].find("/") + protocol_index + 2
+                )
+                port_index = (
+                    console_url[protocol_index + 2 : suffix_index].find(":")
+                    + protocol_index
+                    + 2
+                )
 
-                if console_url:
-                    # parse console_url
-                    protocol_index = console_url.find("//")
-                    suffix_index = (
-                        console_url[protocol_index + 2 :].find("/") + protocol_index + 2
-                    )
-                    port_index = (
-                        console_url[protocol_index + 2 : suffix_index].find(":")
-                        + protocol_index
-                        + 2
+                if protocol_index < 0 or port_index < 0 or suffix_index < 0:
+                    return (
+                        -vimconn.HTTP_Internal_Server_Error,
+                        "Unexpected response from VIM",
                     )
 
-                    if protocol_index < 0 or port_index < 0 or suffix_index < 0:
-                        return (
-                            -vimconn.HTTP_Internal_Server_Error,
-                            "Unexpected response from VIM",
-                        )
-
-                    console_dict = {
-                        "protocol": console_url[0:protocol_index],
-                        "server": console_url[protocol_index + 2 : port_index],
-                        "port": console_url[port_index:suffix_index],
-                        "suffix": console_url[suffix_index + 1 :],
-                    }
-                    protocol_index += 2
+                console_dict = {
+                    "protocol": console_url[0:protocol_index],
+                    "server": console_url[protocol_index + 2 : port_index],
+                    "port": console_url[port_index:suffix_index],
+                    "suffix": console_url[suffix_index + 1 :],
+                }
+                protocol_index += 2
 
-                    return console_dict
-            raise vimconn.VimConnUnexpectedResponse("Unexpected response from VIM")
-        except (
-            nvExceptions.NotFound,
-            ksExceptions.ClientException,
-            nvExceptions.ClientException,
-            nvExceptions.BadRequest,
-            ConnectionError,
-        ) as e:
-            self._format_exception(e)
+                return console_dict
+        raise vimconn.VimConnUnexpectedResponse("Unexpected response from VIM")
 
     def _delete_ports_by_id_wth_neutron(self, k_id: str) -> None:
         """Neutron delete ports by id.
@@ -2991,6 +2987,10 @@ class vimconnector(vimconn.VimConnector):
         try:
             self.neutron.delete_port(k_id)
 
+        except (neExceptions.ConnectionFailed, ConnectionError) as e:
+            self.logger.error("Error deleting port: {}: {}".format(type(e).__name__, e))
+            # If there is connection error, raise.
+            self._format_exception(e)
         except Exception as e:
             self.logger.error("Error deleting port: {}: {}".format(type(e).__name__, e))
 
@@ -3036,7 +3036,7 @@ class vimconnector(vimconn.VimConnector):
         """
         try:
             if k_id in volumes_to_hold:
-                return
+                return False
 
             if self.cinder.volumes.get(k_id).status != "available":
                 return True
@@ -3045,6 +3045,11 @@ class vimconnector(vimconn.VimConnector):
                 self.cinder.volumes.delete(k_id)
                 created_items[k] = None
 
+        except (cExceptions.ConnectionError, ConnectionError) as e:
+            self.logger.error(
+                "Error deleting volume: {}: {}".format(type(e).__name__, e)
+            )
+            self._format_exception(e)
         except Exception as e:
             self.logger.error(
                 "Error deleting volume: {}: {}".format(type(e).__name__, e)
@@ -3061,6 +3066,11 @@ class vimconnector(vimconn.VimConnector):
             self.neutron.delete_floatingip(k_id)
             created_items[k] = None
 
+        except (neExceptions.ConnectionFailed, ConnectionError) as e:
+            self.logger.error(
+                "Error deleting floating ip: {}: {}".format(type(e).__name__, e)
+            )
+            self._format_exception(e)
         except Exception as e:
             self.logger.error(
                 "Error deleting floating ip: {}: {}".format(type(e).__name__, e)
@@ -3086,6 +3096,11 @@ class vimconnector(vimconn.VimConnector):
                 if k_item == "port":
                     self._delete_ports_by_id_wth_neutron(k_id)
 
+            except (neExceptions.ConnectionFailed, ConnectionError) as e:
+                self.logger.error(
+                    "Error deleting port: {}: {}".format(type(e).__name__, e)
+                )
+                self._format_exception(e)
             except Exception as e:
                 self.logger.error(
                     "Error deleting port: {}: {}".format(type(e).__name__, e)
@@ -3112,6 +3127,16 @@ class vimconnector(vimconn.VimConnector):
                 elif k_item == "floating_ip":
                     self._delete_floating_ip_by_id(k, k_id, created_items)
 
+            except (
+                cExceptions.ConnectionError,
+                neExceptions.ConnectionFailed,
+                ConnectionError,
+                AttributeError,
+                TypeError,
+            ) as e:
+                self.logger.error("Error deleting {}: {}".format(k, e))
+                self._format_exception(e)
+
             except Exception as e:
                 self.logger.error("Error deleting {}: {}".format(k, e))
 
@@ -3133,6 +3158,7 @@ class vimconnector(vimconn.VimConnector):
             if len(key.split(":")) == 2
         }
 
+    @catch_any_exception
     def delete_vminstance(
         self, vm_id: str, created_items: dict = None, volumes_to_hold: list = None
     ) -> None:
@@ -3177,14 +3203,9 @@ class vimconnector(vimconn.VimConnector):
                 if keep_waiting:
                     time.sleep(1)
                     elapsed_time += 1
-
-        except (
-            nvExceptions.NotFound,
-            ksExceptions.ClientException,
-            nvExceptions.ClientException,
-            ConnectionError,
-        ) as e:
-            self._format_exception(e)
+        except (nvExceptions.NotFound, nvExceptions.ResourceNotFound) as e:
+            # If VM does not exist, it does not raise
+            self.logger.warning(f"Error deleting VM: {vm_id} is not found, {str(e)}")
 
     def refresh_vms_status(self, vm_list):
         """Get the status of the virtual machines and their interfaces/ports
@@ -3216,7 +3237,6 @@ class vimconnector(vimconn.VimConnector):
         self.logger.debug(
             "refresh_vms status: Getting tenant VM instance information from VIM"
         )
-
         for vm_id in vm_list:
             vm = {}
 
@@ -3329,122 +3349,111 @@ class vimconnector(vimconn.VimConnector):
 
         return vm_dict
 
+    @catch_any_exception
     def action_vminstance(self, vm_id, action_dict, created_items={}):
         """Send and action over a VM instance from VIM
         Returns None or the console dict if the action was successfully sent to the VIM
         """
         self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
-
-        try:
-            self._reload_connection()
-            server = self.nova.servers.find(id=vm_id)
-
-            if "start" in action_dict:
-                if action_dict["start"] == "rebuild":
-                    server.rebuild()
-                else:
-                    if server.status == "PAUSED":
-                        server.unpause()
-                    elif server.status == "SUSPENDED":
-                        server.resume()
-                    elif server.status == "SHUTOFF":
-                        server.start()
-                    else:
-                        self.logger.debug(
-                            "ERROR : Instance is not in SHUTOFF/PAUSE/SUSPEND state"
-                        )
-                        raise vimconn.VimConnException(
-                            "Cannot 'start' instance while it is in active state",
-                            http_code=vimconn.HTTP_Bad_Request,
-                        )
-
-            elif "pause" in action_dict:
-                server.pause()
-            elif "resume" in action_dict:
-                server.resume()
-            elif "shutoff" in action_dict or "shutdown" in action_dict:
-                self.logger.debug("server status %s", server.status)
-                if server.status == "ACTIVE":
-                    server.stop()
+        self._reload_connection()
+        server = self.nova.servers.find(id=vm_id)
+        if "start" in action_dict:
+            if action_dict["start"] == "rebuild":
+                server.rebuild()
+            else:
+                if server.status == "PAUSED":
+                    server.unpause()
+                elif server.status == "SUSPENDED":
+                    server.resume()
+                elif server.status == "SHUTOFF":
+                    server.start()
                 else:
-                    self.logger.debug("ERROR: VM is not in Active state")
-                    raise vimconn.VimConnException(
-                        "VM is not in active state, stop operation is not allowed",
-                        http_code=vimconn.HTTP_Bad_Request,
+                    self.logger.debug(
+                        "ERROR : Instance is not in SHUTOFF/PAUSE/SUSPEND state"
                     )
-            elif "forceOff" in action_dict:
-                server.stop()  # TODO
-            elif "terminate" in action_dict:
-                server.delete()
-            elif "createImage" in action_dict:
-                server.create_image()
-                # "path":path_schema,
-                # "description":description_schema,
-                # "name":name_schema,
-                # "metadata":metadata_schema,
-                # "imageRef": id_schema,
-                # "disk": {"oneOf":[{"type": "null"}, {"type":"string"}] },
-            elif "rebuild" in action_dict:
-                server.rebuild(server.image["id"])
-            elif "reboot" in action_dict:
-                server.reboot()  # reboot_type="SOFT"
-            elif "console" in action_dict:
-                console_type = action_dict["console"]
-
-                if console_type is None or console_type == "novnc":
-                    console_dict = server.get_vnc_console("novnc")
-                elif console_type == "xvpvnc":
-                    console_dict = server.get_vnc_console(console_type)
-                elif console_type == "rdp-html5":
-                    console_dict = server.get_rdp_console(console_type)
-                elif console_type == "spice-html5":
-                    console_dict = server.get_spice_console(console_type)
-                else:
                     raise vimconn.VimConnException(
-                        "console type '{}' not allowed".format(console_type),
+                        "Cannot 'start' instance while it is in active state",
                         http_code=vimconn.HTTP_Bad_Request,
                     )
+        elif "pause" in action_dict:
+            server.pause()
+        elif "resume" in action_dict:
+            server.resume()
+        elif "shutoff" in action_dict or "shutdown" in action_dict:
+            self.logger.debug("server status %s", server.status)
+            if server.status == "ACTIVE":
+                server.stop()
+            else:
+                self.logger.debug("ERROR: VM is not in Active state")
+                raise vimconn.VimConnException(
+                    "VM is not in active state, stop operation is not allowed",
+                    http_code=vimconn.HTTP_Bad_Request,
+                )
+        elif "forceOff" in action_dict:
+            server.stop()  # TODO
+        elif "terminate" in action_dict:
+            server.delete()
+        elif "createImage" in action_dict:
+            server.create_image()
+            # "path":path_schema,
+            # "description":description_schema,
+            # "name":name_schema,
+            # "metadata":metadata_schema,
+            # "imageRef": id_schema,
+            # "disk": {"oneOf":[{"type": "null"}, {"type":"string"}] },
+        elif "rebuild" in action_dict:
+            server.rebuild(server.image["id"])
+        elif "reboot" in action_dict:
+            server.reboot()  # reboot_type="SOFT"
+        elif "console" in action_dict:
+            console_type = action_dict["console"]
 
-                try:
-                    console_url = console_dict["console"]["url"]
-                    # parse console_url
-                    protocol_index = console_url.find("//")
-                    suffix_index = (
-                        console_url[protocol_index + 2 :].find("/") + protocol_index + 2
-                    )
-                    port_index = (
-                        console_url[protocol_index + 2 : suffix_index].find(":")
-                        + protocol_index
-                        + 2
-                    )
-
-                    if protocol_index < 0 or port_index < 0 or suffix_index < 0:
-                        raise vimconn.VimConnException(
-                            "Unexpected response from VIM " + str(console_dict)
-                        )
+            if console_type is None or console_type == "novnc":
+                console_dict = server.get_vnc_console("novnc")
+            elif console_type == "xvpvnc":
+                console_dict = server.get_vnc_console(console_type)
+            elif console_type == "rdp-html5":
+                console_dict = server.get_rdp_console(console_type)
+            elif console_type == "spice-html5":
+                console_dict = server.get_spice_console(console_type)
+            else:
+                raise vimconn.VimConnException(
+                    "console type '{}' not allowed".format(console_type),
+                    http_code=vimconn.HTTP_Bad_Request,
+                )
 
-                    console_dict2 = {
-                        "protocol": console_url[0:protocol_index],
-                        "server": console_url[protocol_index + 2 : port_index],
-                        "port": int(console_url[port_index + 1 : suffix_index]),
-                        "suffix": console_url[suffix_index + 1 :],
-                    }
+            try:
+                console_url = console_dict["console"]["url"]
+                # parse console_url
+                protocol_index = console_url.find("//")
+                suffix_index = (
+                    console_url[protocol_index + 2 :].find("/") + protocol_index + 2
+                )
+                port_index = (
+                    console_url[protocol_index + 2 : suffix_index].find(":")
+                    + protocol_index
+                    + 2
+                )
 
-                    return console_dict2
-                except Exception:
+                if protocol_index < 0 or port_index < 0 or suffix_index < 0:
                     raise vimconn.VimConnException(
                         "Unexpected response from VIM " + str(console_dict)
                     )
 
-            return None
-        except (
-            ksExceptions.ClientException,
-            nvExceptions.ClientException,
-            nvExceptions.NotFound,
-            ConnectionError,
-        ) as e:
-            self._format_exception(e)
-        # TODO insert exception vimconn.HTTP_Unauthorized
+                console_dict2 = {
+                    "protocol": console_url[0:protocol_index],
+                    "server": console_url[protocol_index + 2 : port_index],
+                    "port": int(console_url[port_index + 1 : suffix_index]),
+                    "suffix": console_url[suffix_index + 1 :],
+                }
+
+                return console_dict2
+            except Exception:
+                raise vimconn.VimConnException(
+                    "Unexpected response from VIM " + str(console_dict)
+                )
+
+        return None
 
     # ###### VIO Specific Changes #########
     def _generate_vlanID(self):
@@ -3649,6 +3658,7 @@ class vimconnector(vimconn.VimConnector):
 
         return error_value, error_text
 
+    @catch_any_exception
     def new_affinity_group(self, affinity_group_data):
         """Adds a server group to VIM
             affinity_group_data contains a dictionary with information, keys:
@@ -3657,55 +3667,29 @@ class vimconnector(vimconn.VimConnector):
                 scope: Only nfvi-node allowed
         Returns the server group identifier"""
         self.logger.debug("Adding Server Group '%s'", str(affinity_group_data))
+        name = affinity_group_data["name"]
+        policy = affinity_group_data["type"]
+        self._reload_connection()
+        new_server_group = self.nova.server_groups.create(name, policy)
+        return new_server_group.id
 
-        try:
-            name = affinity_group_data["name"]
-            policy = affinity_group_data["type"]
-
-            self._reload_connection()
-            new_server_group = self.nova.server_groups.create(name, policy)
-
-            return new_server_group.id
-        except (
-            ksExceptions.ClientException,
-            nvExceptions.ClientException,
-            ConnectionError,
-            KeyError,
-        ) as e:
-            self._format_exception(e)
-
+    @catch_any_exception
     def get_affinity_group(self, affinity_group_id):
         """Obtain server group details from the VIM. Returns the server group detais as a dict"""
         self.logger.debug("Getting flavor '%s'", affinity_group_id)
-        try:
-            self._reload_connection()
-            server_group = self.nova.server_groups.find(id=affinity_group_id)
-
-            return server_group.to_dict()
-        except (
-            nvExceptions.NotFound,
-            nvExceptions.ClientException,
-            ksExceptions.ClientException,
-            ConnectionError,
-        ) as e:
-            self._format_exception(e)
+        self._reload_connection()
+        server_group = self.nova.server_groups.find(id=affinity_group_id)
+        return server_group.to_dict()
 
+    @catch_any_exception
     def delete_affinity_group(self, affinity_group_id):
         """Deletes a server group from the VIM. Returns the old affinity_group_id"""
         self.logger.debug("Getting server group '%s'", affinity_group_id)
-        try:
-            self._reload_connection()
-            self.nova.server_groups.delete(affinity_group_id)
-
-            return affinity_group_id
-        except (
-            nvExceptions.NotFound,
-            ksExceptions.ClientException,
-            nvExceptions.ClientException,
-            ConnectionError,
-        ) as e:
-            self._format_exception(e)
+        self._reload_connection()
+        self.nova.server_groups.delete(affinity_group_id)
+        return affinity_group_id
 
+    @catch_any_exception
     def get_vdu_state(self, vm_id, host_is_required=False) -> list:
         """Getting the state of a VDU.
         Args:
@@ -3717,24 +3701,20 @@ class vimconnector(vimconn.VimConnector):
         """
         self.logger.debug("Getting the status of VM")
         self.logger.debug("VIM VM ID %s", vm_id)
-        try:
-            self._reload_connection()
-            server_dict = self._find_nova_server(vm_id)
-            srv_attr = "OS-EXT-SRV-ATTR:host"
-            host_info = (
-                server_dict[srv_attr] if host_is_required else server_dict.get(srv_attr)
-            )
-            vdu_data = [
-                server_dict["status"],
-                server_dict["flavor"]["id"],
-                host_info,
-                server_dict["OS-EXT-AZ:availability_zone"],
-            ]
-            self.logger.debug("vdu_data %s", vdu_data)
-            return vdu_data
-
-        except Exception as e:
-            self._format_exception(e)
+        self._reload_connection()
+        server_dict = self._find_nova_server(vm_id)
+        srv_attr = "OS-EXT-SRV-ATTR:host"
+        host_info = (
+            server_dict[srv_attr] if host_is_required else server_dict.get(srv_attr)
+        )
+        vdu_data = [
+            server_dict["status"],
+            server_dict["flavor"]["id"],
+            host_info,
+            server_dict["OS-EXT-AZ:availability_zone"],
+        ]
+        self.logger.debug("vdu_data %s", vdu_data)
+        return vdu_data
 
     def check_compute_availability(self, host, server_flavor_details):
         self._reload_connection()
@@ -3792,6 +3772,7 @@ class vimconnector(vimconn.VimConnector):
                         az_check["zone_check"] = True
         return az_check
 
+    @catch_any_exception
     def migrate_instance(self, vm_id, compute_host=None):
         """
         Migrate a vdu
@@ -3805,78 +3786,72 @@ class vimconnector(vimconn.VimConnector):
         server_flavor_id = instance_state[1]
         server_hypervisor_name = instance_state[2]
         server_availability_zone = instance_state[3]
-        try:
-            server_flavor = self.nova.flavors.find(id=server_flavor_id).to_dict()
-            server_flavor_details = [
-                server_flavor["ram"],
-                server_flavor["disk"],
-                server_flavor["vcpus"],
-            ]
-            if compute_host == server_hypervisor_name:
-                raise vimconn.VimConnException(
-                    "Unable to migrate instance '{}' to the same host '{}'".format(
-                        vm_id, compute_host
-                    ),
-                    http_code=vimconn.HTTP_Bad_Request,
-                )
-            az_status = self.check_availability_zone(
-                server_availability_zone,
-                server_flavor_details,
-                server_hypervisor_name,
-                compute_host,
+        server_flavor = self.nova.flavors.find(id=server_flavor_id).to_dict()
+        server_flavor_details = [
+            server_flavor["ram"],
+            server_flavor["disk"],
+            server_flavor["vcpus"],
+        ]
+        if compute_host == server_hypervisor_name:
+            raise vimconn.VimConnException(
+                "Unable to migrate instance '{}' to the same host '{}'".format(
+                    vm_id, compute_host
+                ),
+                http_code=vimconn.HTTP_Bad_Request,
             )
-            availability_zone_check = az_status["zone_check"]
-            available_compute_id = az_status.get("compute_availability")
+        az_status = self.check_availability_zone(
+            server_availability_zone,
+            server_flavor_details,
+            server_hypervisor_name,
+            compute_host,
+        )
+        availability_zone_check = az_status["zone_check"]
+        available_compute_id = az_status.get("compute_availability")
 
-            if availability_zone_check is False:
-                raise vimconn.VimConnException(
-                    "Unable to migrate instance '{}' to a different availability zone".format(
-                        vm_id
-                    ),
-                    http_code=vimconn.HTTP_Bad_Request,
-                )
-            if available_compute_id is not None:
-                # disk_over_commit parameter for live_migrate method is not valid for Nova API version >= 2.25
-                self.nova.servers.live_migrate(
-                    server=vm_id,
-                    host=available_compute_id,
-                    block_migration=True,
-                )
-                state = "MIGRATING"
-                changed_compute_host = ""
-                if state == "MIGRATING":
-                    vm_state = self.__wait_for_vm(vm_id, "ACTIVE")
-                    changed_compute_host = self.get_vdu_state(
-                        vm_id, host_is_required=True
-                    )[2]
-                if vm_state and changed_compute_host == available_compute_id:
-                    self.logger.debug(
-                        "Instance '{}' migrated to the new compute host '{}'".format(
-                            vm_id, changed_compute_host
-                        )
-                    )
-                    return state, available_compute_id
-                else:
-                    raise vimconn.VimConnException(
-                        "Migration Failed. Instance '{}' not moved to the new host {}".format(
-                            vm_id, available_compute_id
-                        ),
-                        http_code=vimconn.HTTP_Bad_Request,
+        if availability_zone_check is False:
+            raise vimconn.VimConnException(
+                "Unable to migrate instance '{}' to a different availability zone".format(
+                    vm_id
+                ),
+                http_code=vimconn.HTTP_Bad_Request,
+            )
+        if available_compute_id is not None:
+            # disk_over_commit parameter for live_migrate method is not valid for Nova API version >= 2.25
+            self.nova.servers.live_migrate(
+                server=vm_id,
+                host=available_compute_id,
+                block_migration=True,
+            )
+            state = "MIGRATING"
+            changed_compute_host = ""
+            if state == "MIGRATING":
+                vm_state = self.__wait_for_vm(vm_id, "ACTIVE")
+                changed_compute_host = self.get_vdu_state(vm_id, host_is_required=True)[
+                    2
+                ]
+            if vm_state and changed_compute_host == available_compute_id:
+                self.logger.debug(
+                    "Instance '{}' migrated to the new compute host '{}'".format(
+                        vm_id, changed_compute_host
                     )
+                )
+                return state, available_compute_id
             else:
                 raise vimconn.VimConnException(
-                    "Compute '{}' not available or does not have enough resources to migrate the instance".format(
-                        available_compute_id
+                    "Migration Failed. Instance '{}' not moved to the new host {}".format(
+                        vm_id, available_compute_id
                     ),
                     http_code=vimconn.HTTP_Bad_Request,
                 )
-        except (
-            nvExceptions.BadRequest,
-            nvExceptions.ClientException,
-            nvExceptions.NotFound,
-        ) as e:
-            self._format_exception(e)
+        else:
+            raise vimconn.VimConnException(
+                "Compute '{}' not available or does not have enough resources to migrate the instance".format(
+                    available_compute_id
+                ),
+                http_code=vimconn.HTTP_Bad_Request,
+            )
 
+    @catch_any_exception
     def resize_instance(self, vm_id, new_flavor_id):
         """
         For resizing the vm based on the given
@@ -3891,37 +3866,30 @@ class vimconnector(vimconn.VimConnector):
         instance_status, old_flavor_id, compute_host, az = self.get_vdu_state(vm_id)
         old_flavor_disk = self.nova.flavors.find(id=old_flavor_id).to_dict()["disk"]
         new_flavor_disk = self.nova.flavors.find(id=new_flavor_id).to_dict()["disk"]
-        try:
-            if instance_status == "ACTIVE" or instance_status == "SHUTOFF":
-                if old_flavor_disk > new_flavor_disk:
+        if instance_status == "ACTIVE" or instance_status == "SHUTOFF":
+            if old_flavor_disk > new_flavor_disk:
+                raise nvExceptions.BadRequest(
+                    400,
+                    message="Server disk resize failed. Resize to lower disk flavor is not allowed",
+                )
+            else:
+                self.nova.servers.resize(server=vm_id, flavor=new_flavor_id)
+                vm_state = self.__wait_for_vm(vm_id, "VERIFY_RESIZE")
+                if vm_state:
+                    instance_resized_status = self.confirm_resize(vm_id)
+                    return instance_resized_status
+                else:
                     raise nvExceptions.BadRequest(
-                        400,
-                        message="Server disk resize failed. Resize to lower disk flavor is not allowed",
+                        409,
+                        message="Cannot 'resize' vm_state is in ERROR",
                     )
-                else:
-                    self.nova.servers.resize(server=vm_id, flavor=new_flavor_id)
-                    vm_state = self.__wait_for_vm(vm_id, "VERIFY_RESIZE")
-                    if vm_state:
-                        instance_resized_status = self.confirm_resize(vm_id)
-                        return instance_resized_status
-                    else:
-                        raise nvExceptions.BadRequest(
-                            409,
-                            message="Cannot 'resize' vm_state is in ERROR",
-                        )
 
-            else:
-                self.logger.debug("ERROR : Instance is not in ACTIVE or SHUTOFF state")
-                raise nvExceptions.BadRequest(
-                    409,
-                    message="Cannot 'resize' instance while it is in vm_state resized",
-                )
-        except (
-            nvExceptions.BadRequest,
-            nvExceptions.ClientException,
-            nvExceptions.NotFound,
-        ) as e:
-            self._format_exception(e)
+        else:
+            self.logger.debug("ERROR : Instance is not in ACTIVE or SHUTOFF state")
+            raise nvExceptions.BadRequest(
+                409,
+                message="Cannot 'resize' instance while it is in vm_state resized",
+            )
 
     def confirm_resize(self, vm_id):
         """
@@ -3951,11 +3919,7 @@ class vimconnector(vimconn.VimConnector):
                 self.logger.warning(str(e.message))
             all_ports = self.neutron.list_ports()
             return all_servers, all_ports
-        except (
-            vimconn.VimConnException,
-            vimconn.VimConnNotFoundException,
-            vimconn.VimConnConnectionException,
-        ) as e:
+        except Exception as e:
             raise vimconn.VimConnException(
                 f"Exception in monitoring while getting VMs and ports status: {str(e)}"
             )
diff --git a/releasenotes/notes/fix_bug_2158_2254-86a20d2b2a6ca5a9.yaml b/releasenotes/notes/fix_bug_2158_2254-86a20d2b2a6ca5a9.yaml
new file mode 100644 (file)
index 0000000..95715d9
--- /dev/null
@@ -0,0 +1,23 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#######################################################################################
+---
+fixes:
+  - |
+    Fix Bug 2158 If VIM is not reachable NS delete operation should fail and Bug 2254
+    VNF scale up operation should fail if operation is not completed by arranging exceptions
+
+