Bug 1643 fix
[osm/N2VC.git] / n2vc / n2vc_juju_conn.py
index 99661f5..af40aee 100644 (file)
@@ -29,6 +29,8 @@ from n2vc.exceptions import (
     N2VCException,
     N2VCConnectionException,
     N2VCExecutionException,
+    N2VCApplicationExists,
+    JujuApplicationExists,
     # N2VCNotFound,
     MethodNotImplemented,
 )
@@ -37,6 +39,7 @@ from n2vc.n2vc_conn import obj_to_dict, obj_to_yaml
 from n2vc.libjuju import Libjuju
 from n2vc.store import MotorStore
 from n2vc.vca.connection import get_connection
+from retrying_async import retry
 
 
 class N2VCJujuConnector(N2VCConnector):
@@ -143,15 +146,18 @@ class N2VCJujuConnector(N2VCConnector):
             libjuju = await self._get_libjuju(vca_id)
             for model_name in vcastatus:
                 # Adding executed actions
-                vcastatus[model_name]["executedActions"] = \
-                    await libjuju.get_executed_actions(model_name)
+                vcastatus[model_name][
+                    "executedActions"
+                ] = await libjuju.get_executed_actions(model_name)
                 for application in vcastatus[model_name]["applications"]:
                     # Adding application actions
-                    vcastatus[model_name]["applications"][application]["actions"] = \
-                        await libjuju.get_actions(application, model_name)
+                    vcastatus[model_name]["applications"][application][
+                        "actions"
+                    ] = await libjuju.get_actions(application, model_name)
                     # Adding application configs
-                    vcastatus[model_name]["applications"][application]["configs"] = \
-                        await libjuju.get_application_configs(model_name, application)
+                    vcastatus[model_name]["applications"][application][
+                        "configs"
+                    ] = await libjuju.get_application_configs(model_name, application)
         except Exception as e:
             self.log.debug("Error in updating vca status: {}".format(str(e)))
 
@@ -361,6 +367,9 @@ class N2VCJujuConnector(N2VCConnector):
 
         return ee_id
 
+    # 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)
     async def install_configuration_sw(
         self,
         ee_id: str,
@@ -371,6 +380,8 @@ class N2VCJujuConnector(N2VCConnector):
         config: dict = None,
         num_units: int = 1,
         vca_id: str = None,
+        scaling_out: bool = False,
+        vca_type: str = None,
     ):
         """
         Install the software inside the execution environment identified by ee_id
@@ -392,6 +403,8 @@ class N2VCJujuConnector(N2VCConnector):
         :param: config: Dictionary with deployment config information.
         :param: num_units: Number of units to deploy of a particular charm.
         :param: vca_id: VCA ID
+        :param: scaling_out: Boolean to indicate if it is a scaling out operation
+        :param: vca_type: VCA type
         """
 
         self.log.info(
@@ -450,20 +463,36 @@ class N2VCJujuConnector(N2VCConnector):
             full_path = self.fs.path + "/" + artifact_path
 
         try:
-            await libjuju.deploy_charm(
-                model_name=model_name,
-                application_name=application_name,
-                path=full_path,
-                machine_id=machine_id,
-                db_dict=db_dict,
-                progress_timeout=progress_timeout,
-                total_timeout=total_timeout,
-                config=config,
-                num_units=num_units,
+            if vca_type == "native_charm" and await libjuju.check_application_exists(
+                model_name, application_name
+            ):
+                await libjuju.add_unit(
+                    application_name=application_name,
+                    model_name=model_name,
+                    machine_id=machine_id,
+                    db_dict=db_dict,
+                    progress_timeout=progress_timeout,
+                    total_timeout=total_timeout,
+                )
+            else:
+                await libjuju.deploy_charm(
+                    model_name=model_name,
+                    application_name=application_name,
+                    path=full_path,
+                    machine_id=machine_id,
+                    db_dict=db_dict,
+                    progress_timeout=progress_timeout,
+                    total_timeout=total_timeout,
+                    config=config,
+                    num_units=num_units,
+                )
+        except JujuApplicationExists as e:
+            raise N2VCApplicationExists(
+                message="Error deploying charm into ee={} : {}".format(ee_id, e.message)
             )
         except Exception as e:
             raise N2VCException(
-                message="Error desploying charm into ee={} : {}".format(ee_id, e)
+                message="Error deploying charm into ee={} : {}".format(ee_id, e)
             )
 
         self.log.info("Configuration sw installed")
@@ -816,6 +845,7 @@ class N2VCJujuConnector(N2VCConnector):
         db_dict: dict = None,
         total_timeout: float = None,
         scaling_in: bool = False,
+        vca_type: str = None,
         vca_id: str = None,
     ):
         """
@@ -827,7 +857,8 @@ class N2VCJujuConnector(N2VCConnector):
                             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 is it a scaling in operation
+        :param: scaling_in: Boolean to indicate if it is a scaling in operation
+        :param: vca_type: VCA type
         :param: vca_id: VCA ID
         """
         self.log.info("Deleting execution environment ee_id={}".format(ee_id))
@@ -839,17 +870,24 @@ class N2VCJujuConnector(N2VCConnector):
                 message="ee_id is mandatory", bad_args=["ee_id"]
             )
 
-        model_name, application_name, _machine_id = self._get_ee_id_components(
+        model_name, application_name, machine_id = self._get_ee_id_components(
             ee_id=ee_id
         )
         try:
             if not scaling_in:
                 # destroy the model
-                # TODO: should this be removed?
                 await libjuju.destroy_model(
                     model_name=model_name,
                     total_timeout=total_timeout,
                 )
+            elif vca_type == "native_charm" and scaling_in:
+                # destroy the unit in the application
+                await libjuju.destroy_unit(
+                    application_name=application_name,
+                    model_name=model_name,
+                    machine_id=machine_id,
+                    total_timeout=total_timeout,
+                )
             else:
                 # destroy the application
                 await libjuju.destroy_application(
@@ -875,6 +913,7 @@ class N2VCJujuConnector(N2VCConnector):
         progress_timeout: float = None,
         total_timeout: float = None,
         vca_id: str = None,
+        vca_type: str = None,
     ) -> str:
         """
         Execute a primitive in the execution environment
@@ -893,6 +932,7 @@ class N2VCJujuConnector(N2VCConnector):
         :param: progress_timeout: Progress timeout
         :param: total_timeout: Total timeout
         :param: vca_id: VCA ID
+        :param: vca_type: VCA type
         :returns str: primitive result, if ok. It raises exceptions in case of fail
         """
 
@@ -919,8 +959,12 @@ class N2VCJujuConnector(N2VCConnector):
             (
                 model_name,
                 application_name,
-                _machine_id,
+                machine_id,
             ) = N2VCJujuConnector._get_ee_id_components(ee_id=ee_id)
+            # To run action on the leader unit in libjuju.execute_action function,
+            # machine_id must be set to None if vca_type is not native_charm
+            if vca_type != "native_charm":
+                machine_id = None
         except Exception:
             raise N2VCBadArgumentsException(
                 message="ee_id={} is not a valid execution environment id".format(
@@ -1000,6 +1044,7 @@ class N2VCJujuConnector(N2VCConnector):
                     application_name=application_name,
                     action_name=primitive_name,
                     db_dict=db_dict,
+                    machine_id=machine_id,
                     progress_timeout=progress_timeout,
                     total_timeout=total_timeout,
                     **params_dict