Pin black version in tox.ini to 23.12.1
[osm/N2VC.git] / n2vc / n2vc_juju_conn.py
index cbca396..f28a9bd 100644 (file)
@@ -37,7 +37,7 @@ from n2vc.exceptions import (
 )
 from n2vc.n2vc_conn import N2VCConnector
 from n2vc.n2vc_conn import obj_to_dict, obj_to_yaml
-from n2vc.libjuju import Libjuju
+from n2vc.libjuju import Libjuju, retry_callback
 from n2vc.store import MotorStore
 from n2vc.utils import get_ee_id_components, generate_random_alfanum_string
 from n2vc.vca.connection import get_connection
@@ -61,7 +61,6 @@ class N2VCJujuConnector(N2VCConnector):
         db: object,
         fs: object,
         log: object = None,
-        loop: object = None,
         on_update_db=None,
     ):
         """
@@ -70,14 +69,11 @@ class N2VCJujuConnector(N2VCConnector):
         :param: db: Database object from osm_common
         :param: fs: Filesystem object from osm_common
         :param: log: Logger
-        :param: loop: Asyncio loop
         :param: on_update_db: Callback function to be called for updating the database.
         """
 
         # parent class constructor
-        N2VCConnector.__init__(
-            self, db=db, fs=fs, log=log, loop=loop, on_update_db=on_update_db
-        )
+        N2VCConnector.__init__(self, db=db, fs=fs, log=log, on_update_db=on_update_db)
 
         # silence websocket traffic log
         logging.getLogger("websockets.protocol").setLevel(logging.INFO)
@@ -88,7 +84,7 @@ class N2VCJujuConnector(N2VCConnector):
 
         db_uri = EnvironConfig(prefixes=["OSMLCM_", "OSMMON_"]).get("database_uri")
         self._store = MotorStore(db_uri)
-        self.loading_libjuju = asyncio.Lock(loop=self.loop)
+        self.loading_libjuju = asyncio.Lock()
         self.delete_namespace_locks = {}
         self.log.info("N2VC juju connector initialized")
 
@@ -359,7 +355,13 @@ class N2VCJujuConnector(N2VCConnector):
 
     # In case of native_charm is being deployed, if JujuApplicationExists error happens
     # it will try to add_unit
-    @retry(attempts=3, delay=5, retry_exceptions=(N2VCApplicationExists,), timeout=None)
+    @retry(
+        attempts=3,
+        delay=5,
+        retry_exceptions=(N2VCApplicationExists,),
+        timeout=None,
+        callback=retry_callback,
+    )
     async def install_configuration_sw(
         self,
         ee_id: str,
@@ -772,7 +774,7 @@ class N2VCJujuConnector(N2VCConnector):
         self.log.info("Deleting namespace={}".format(namespace))
         will_not_delete = False
         if namespace not in self.delete_namespace_locks:
-            self.delete_namespace_locks[namespace] = asyncio.Lock(loop=self.loop)
+            self.delete_namespace_locks[namespace] = asyncio.Lock()
         delete_lock = self.delete_namespace_locks[namespace]
 
         while delete_lock.locked():
@@ -834,6 +836,7 @@ class N2VCJujuConnector(N2VCConnector):
         scaling_in: bool = False,
         vca_type: str = None,
         vca_id: str = None,
+        application_to_delete: str = None,
     ):
         """
         Delete an execution environment
@@ -843,10 +846,11 @@ class N2VCJujuConnector(N2VCConnector):
                             {collection: <str>, filter: {},  path: <str>},
                             e.g. {collection: "nsrs", filter:
                                 {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
-        :param: total_timeout: Total timeout
-        :param: scaling_in: Boolean to indicate if it is a scaling in operation
-        :param: vca_type: VCA type
-        :param: vca_id: VCA ID
+        :param total_timeout: Total timeout
+        :param scaling_in: Boolean to indicate if it is a scaling in operation
+        :param vca_type: VCA type
+        :param vca_id: VCA ID
+        :param application_to_delete: name of the single application to be deleted
         """
         self.log.info("Deleting execution environment ee_id={}".format(ee_id))
         libjuju = await self._get_libjuju(vca_id)
@@ -861,7 +865,26 @@ class N2VCJujuConnector(N2VCConnector):
             ee_id=ee_id
         )
         try:
-            if not scaling_in:
+            if application_to_delete == application_name:
+                # destroy the application
+                await libjuju.destroy_application(
+                    model_name=model_name,
+                    application_name=application_name,
+                    total_timeout=total_timeout,
+                )
+                # if model is empty delete it
+                controller = await libjuju.get_controller()
+                model = await libjuju.get_model(
+                    controller=controller,
+                    model_name=model_name,
+                )
+                if not model.applications:
+                    self.log.info("Model {} is empty, deleting it".format(model_name))
+                    await libjuju.destroy_model(
+                        model_name=model_name,
+                        total_timeout=total_timeout,
+                    )
+            elif not scaling_in:
                 # destroy the model
                 await libjuju.destroy_model(
                     model_name=model_name, total_timeout=total_timeout
@@ -1148,11 +1171,11 @@ class N2VCJujuConnector(N2VCConnector):
             if not self.libjuju:
                 async with self.loading_libjuju:
                     vca_connection = await get_connection(self._store)
-                    self.libjuju = Libjuju(vca_connection, loop=self.loop, log=self.log)
+                    self.libjuju = Libjuju(vca_connection, log=self.log)
             return self.libjuju
         else:
             vca_connection = await get_connection(self._store, vca_id)
-            return Libjuju(vca_connection, loop=self.loop, log=self.log, n2vc=self)
+            return Libjuju(vca_connection, log=self.log, n2vc=self)
 
     def _write_ee_id_db(self, db_dict: dict, ee_id: str):
         # write ee_id to database: _admin.deployed.VCA.x
@@ -1536,6 +1559,6 @@ class N2VCJujuConnector(N2VCConnector):
         :param: vca_id: VCA ID
         """
         vca_connection = await get_connection(self._store, vca_id=vca_id)
-        libjuju = Libjuju(vca_connection, loop=self.loop, log=self.log, n2vc=self)
+        libjuju = Libjuju(vca_connection, log=self.log, n2vc=self)
         controller = await libjuju.get_controller()
         await libjuju.disconnect_controller(controller)