Bug 2174: VCA Update is not implemented

Fix: Handle the edit operation.
If no update on the VCA configuration is given as input, then the operation is
marked as completed.
Otherwise the validation of the new VCA configuration is performed,
which may cause the edit operation to fail.

Change-Id: Id13604664df3594874877d0cb2ad13b1ce6d2353
Signed-off-by: Dario Faccin <dario.faccin@canonical.com>
diff --git a/osm_lcm/vim_sdn.py b/osm_lcm/vim_sdn.py
index d95df94..41a16e5 100644
--- a/osm_lcm/vim_sdn.py
+++ b/osm_lcm/vim_sdn.py
@@ -1466,6 +1466,33 @@
         )
         return db_vca
 
+    async def _validate_vca(self, db_vca_id: str) -> None:
+        task = asyncio.ensure_future(
+            asyncio.wait_for(
+                self.n2vc.validate_vca(db_vca_id),
+                timeout=self.timeout_create,
+            )
+        )
+        await asyncio.wait([task], return_when=asyncio.FIRST_COMPLETED)
+        if task.exception():
+            raise task.exception()
+
+    def _is_vca_config_update(self, update_options) -> bool:
+        return any(
+            word in update_options.keys()
+            for word in [
+                "cacert",
+                "endpoints",
+                "lxd-cloud",
+                "lxd-credentials",
+                "k8s-cloud",
+                "k8s-credentials",
+                "model-config",
+                "user",
+                "secret",
+            ]
+        )
+
     async def create(self, vca_content, order_id):
         op_id = vca_content.pop("op_id", None)
         if not self.lcm_tasks.lock_HA("vca", "create", op_id):
@@ -1484,16 +1511,7 @@
             )
             db_vca = self._get_vca_by_id(vca_id)
 
-            task = asyncio.ensure_future(
-                asyncio.wait_for(
-                    self.n2vc.validate_vca(db_vca["_id"]),
-                    timeout=self.timeout_create,
-                )
-            )
-
-            await asyncio.wait([task], return_when=asyncio.FIRST_COMPLETED)
-            if task.exception():
-                raise task.exception()
+            await self._validate_vca(db_vca["_id"])
             self.logger.debug(
                 "Task vca_create={} {}".format(
                     vca_id, "vca registered and validated successfully"
@@ -1536,6 +1554,70 @@
                 )
             self.lcm_tasks.remove("vca", vca_id, order_id)
 
+    async def edit(self, vca_content, order_id):
+        op_id = vca_content.pop("op_id", None)
+        if not self.lcm_tasks.lock_HA("vca", "edit", op_id):
+            return
+
+        vca_id = vca_content["_id"]
+        self.logger.debug("Task vca_edit={} {}".format(vca_id, "Enter"))
+
+        db_vca = None
+        db_vca_update = {}
+
+        operation_state = "FAILED"
+        operation_details = ""
+        try:
+            self.logger.debug(
+                "Task vca_edit={} {}".format(vca_id, "Getting vca from db")
+            )
+            db_vca = self._get_vca_by_id(vca_id)
+            if self._is_vca_config_update(vca_content):
+                await self._validate_vca(db_vca["_id"])
+                self.logger.debug(
+                    "Task vca_edit={} {}".format(
+                        vca_id, "vca registered and validated successfully"
+                    )
+                )
+                db_vca_update["_admin.operationalState"] = "ENABLED"
+                db_vca_update["_admin.detailed-status"] = "Connectivity: ok"
+
+            operation_details = "Edited"
+            operation_state = "COMPLETED"
+
+            self.logger.debug(
+                "Task vca_edit={} {}".format(
+                    vca_id, "Done. Result: {}".format(operation_state)
+                )
+            )
+
+        except Exception as e:
+            error_msg = "Failed with exception: {}".format(e)
+            self.logger.error("Task vca_edit={} {}".format(vca_id, error_msg))
+            db_vca_update["_admin.operationalState"] = "ERROR"
+            db_vca_update["_admin.detailed-status"] = error_msg
+            operation_state = "FAILED"
+            operation_details = error_msg
+        finally:
+            try:
+                self.update_db_2("vca", vca_id, db_vca_update)
+
+                # Register the operation and unlock
+                self.lcm_tasks.unlock_HA(
+                    "vca",
+                    "edit",
+                    op_id,
+                    operationState=operation_state,
+                    detailed_status=operation_details,
+                )
+            except DbException as e:
+                self.logger.error(
+                    "Task vca_edit={} {}".format(
+                        vca_id, "Cannot update database: {}".format(e)
+                    )
+                )
+            self.lcm_tasks.remove("vca", vca_id, order_id)
+
     async def delete(self, vca_content, order_id):
 
         # HA tasks and backward compatibility: