Fix bug 1216: Force model deletion 89/9889/6
authorDavid Garcia <david.garcia@canonical.com>
Tue, 29 Sep 2020 17:48:13 +0000 (19:48 +0200)
committerDavid Garcia <david.garcia@canonical.com>
Wed, 21 Oct 2020 14:24:02 +0000 (16:24 +0200)
Change-Id: I3f41eead305349eba5d404f5f3d61d33f0536aca
Signed-off-by: David Garcia <david.garcia@canonical.com>
n2vc/libjuju.py
n2vc/tests/unit/test_libjuju.py
n2vc/tests/unit/utils.py
requirements.txt
setup.py

index 28474a0..a457309 100644 (file)
@@ -817,18 +817,6 @@ class Libjuju:
             self.log.debug("Destroying model {}".format(model_name))
             uuid = model.info.uuid
 
-            # Destroy machines
-            machines = await model.get_machines()
-            for machine_id in machines:
-                try:
-                    await self.destroy_machine(
-                        model, machine_id=machine_id, total_timeout=total_timeout,
-                    )
-                except asyncio.CancelledError:
-                    raise
-                except Exception:
-                    pass
-
             # Disconnect model
             await self.disconnect_model(model)
 
@@ -836,32 +824,24 @@ class Libjuju:
             if model_name in self.models:
                 self.models.remove(model_name)
 
-            await controller.destroy_model(uuid)
+            await controller.destroy_model(uuid, force=True, max_wait=0)
 
             # Wait until model is destroyed
             self.log.debug("Waiting for model {} to be destroyed...".format(model_name))
-            last_exception = ""
 
             if total_timeout is None:
                 total_timeout = 3600
             end = time.time() + total_timeout
             while time.time() < end:
-                try:
-                    models = await controller.list_models()
-                    if model_name not in models:
-                        self.log.debug(
-                            "The model {} ({}) was destroyed".format(model_name, uuid)
-                        )
-                        return
-                except asyncio.CancelledError:
-                    raise
-                except Exception as e:
-                    last_exception = e
+                models = await controller.list_models()
+                if model_name not in models:
+                    self.log.debug(
+                        "The model {} ({}) was destroyed".format(model_name, uuid)
+                    )
+                    return
                 await asyncio.sleep(5)
             raise Exception(
-                "Timeout waiting for model {} to be destroyed {}".format(
-                    model_name, last_exception
-                )
+                "Timeout waiting for model {} to be destroyed".format(model_name)
             )
         finally:
             await self.disconnect_controller(controller)
@@ -884,32 +864,32 @@ class Libjuju:
         else:
             self.log.warning("Application not found: {}".format(application_name))
 
-    async def destroy_machine(
-        self, model: Model, machine_id: str, total_timeout: float = 3600
-    ):
-        """
-        Destroy machine
-
-        :param: model:          Model object
-        :param: machine_id:     Machine id
-        :param: total_timeout:  Timeout in seconds
-        """
-        machines = await model.get_machines()
-        if machine_id in machines:
-            machine = machines[machine_id]
-            await machine.destroy(force=True)
-            # max timeout
-            end = time.time() + total_timeout
-
-            # wait for machine removal
-            machines = await model.get_machines()
-            while machine_id in machines and time.time() < end:
-                self.log.debug("Waiting for machine {} is destroyed".format(machine_id))
-                await asyncio.sleep(0.5)
-                machines = await model.get_machines()
-            self.log.debug("Machine destroyed: {}".format(machine_id))
-        else:
-            self.log.debug("Machine not found: {}".format(machine_id))
+    async def destroy_machine(
+        self, model: Model, machine_id: str, total_timeout: float = 3600
+    ):
+        """
+        Destroy machine
+
+        :param: model:          Model object
+        :param: machine_id:     Machine id
+        :param: total_timeout:  Timeout in seconds
+        """
+        machines = await model.get_machines()
+        if machine_id in machines:
+            machine = machines[machine_id]
+            await machine.destroy(force=True)
+            # max timeout
+            end = time.time() + total_timeout
+
+            # wait for machine removal
+            machines = await model.get_machines()
+            while machine_id in machines and time.time() < end:
+                self.log.debug("Waiting for machine {} is destroyed".format(machine_id))
+                await asyncio.sleep(0.5)
+                machines = await model.get_machines()
+            self.log.debug("Machine destroyed: {}".format(machine_id))
+        else:
+            self.log.debug("Machine not found: {}".format(machine_id))
 
     async def configure_application(
         self, model_name: str, application_name: str, config: dict = None
index 123da4a..a384e44 100644 (file)
@@ -866,37 +866,37 @@ class AddRelationTest(LibjujuTestCase):
 # TODO destroy_model testcase
 
 
-@asynctest.mock.patch("juju.model.Model.get_machines")
-@asynctest.mock.patch("logging.Logger.debug")
-class DestroyMachineTest(LibjujuTestCase):
-    def setUp(self):
-        super(DestroyMachineTest, self).setUp()
-
-    def test_success(
-        self, mock_debug, mock_get_machines,
-    ):
-        mock_get_machines.side_effect = [
-            {"machine": FakeMachine()},
-            {"machine": FakeMachine()},
-            {},
-        ]
-        self.loop.run_until_complete(
-            self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
-        )
-        calls = [
-            asynctest.call("Waiting for machine machine is destroyed"),
-            asynctest.call("Machine destroyed: machine"),
-        ]
-        mock_debug.assert_has_calls(calls)
-
-    def test_no_machine(
-        self, mock_debug, mock_get_machines,
-    ):
-        mock_get_machines.return_value = {}
-        self.loop.run_until_complete(
-            self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
-        )
-        mock_debug.assert_called_with("Machine not found: machine")
+@asynctest.mock.patch("juju.model.Model.get_machines")
+@asynctest.mock.patch("logging.Logger.debug")
+class DestroyMachineTest(LibjujuTestCase):
+    def setUp(self):
+        super(DestroyMachineTest, self).setUp()
+
+#     def test_success_manual_machine(
+        self, mock_debug, mock_get_machines,
+    ):
+        mock_get_machines.side_effect = [
+#             {"machine": FakeManualMachine()},
+#             {"machine": FakeManualMachine()},
+            {},
+        ]
+        self.loop.run_until_complete(
+            self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
+        )
+        calls = [
+            asynctest.call("Waiting for machine machine is destroyed"),
+            asynctest.call("Machine destroyed: machine"),
+        ]
+        mock_debug.assert_has_calls(calls)
+
+    def test_no_machine(
+        self, mock_debug, mock_get_machines,
+    ):
+        mock_get_machines.return_value = {}
+        self.loop.run_until_complete(
+#             self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
+        )
+        mock_debug.assert_called_with("Machine not found: machine")
 
 
 @asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
index ee4dd96..d960c70 100644 (file)
@@ -56,6 +56,18 @@ class FakeMachine(MagicMock):
     dns_name = "FAKE ENDPOINT"
     model_name = "FAKE MODEL"
     entity_type = "machine"
+    safe_data = {"instance-id": "myid"}
+
+    async def destroy(self, force):
+        pass
+
+
+class FakeManualMachine(MagicMock):
+    entity_id = "2"
+    dns_name = "FAKE ENDPOINT"
+    model_name = "FAKE MODEL"
+    entity_type = "machine"
+    safe_data = {"instance-id": "manual:myid"}
 
     async def destroy(self, force):
         pass
index 4f467fb..e8c4db4 100644 (file)
@@ -13,6 +13,6 @@
 #     limitations under the License.
 
 git+https://osm.etsi.org/gerrit/osm/common.git#egg=osm-common
-juju==2.8.2
+juju==2.8.4
 pyasn1>=0.4.4
 kubernetes==10.0.1
index 7a6b451..7a4fe87 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -23,7 +23,7 @@ setup(
     packages=find_packages(
         exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
     install_requires=[
-        'juju==2.8.2',
+        'juju==2.8.4',
         'pyasn1>=0.4.4',
         'kubernetes==10.0.1'
     ],