Fix bug 1216: Remove machines only for native charms

Updates revision of Python libjuju to 2.8.4

Change-Id: I3f41eead305349eba5d404f5f3d61d33f0536aca
Signed-off-by: David Garcia <david.garcia@canonical.com>
diff --git a/n2vc/libjuju.py b/n2vc/libjuju.py
index 237a401..d998475 100644
--- a/n2vc/libjuju.py
+++ b/n2vc/libjuju.py
@@ -765,18 +765,6 @@
             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)
 
@@ -784,32 +772,24 @@
             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)
@@ -832,32 +812,32 @@
         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
+    # 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
+    #     :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))
+    #         # 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
diff --git a/n2vc/tests/unit/test_libjuju.py b/n2vc/tests/unit/test_libjuju.py
index 5669959..b9cc529 100644
--- a/n2vc/tests/unit/test_libjuju.py
+++ b/n2vc/tests/unit/test_libjuju.py
@@ -753,37 +753,37 @@
 # 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()
+# @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_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")
+#     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")
diff --git a/n2vc/tests/unit/utils.py b/n2vc/tests/unit/utils.py
index ee4dd96..d960c70 100644
--- a/n2vc/tests/unit/utils.py
+++ b/n2vc/tests/unit/utils.py
@@ -56,6 +56,18 @@
     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