X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=n2vc%2Fk8s_juju_conn.py;h=25294807036842262b57b0e48498e3353413f867;hb=a202877e73c3712e8b09dcc5649dcec43b967759;hp=149947ddefbb58523d4e300a16947d9235722c3f;hpb=d8d4b6e70c0e4410a4b5c274faecd37ee821f3b7;p=osm%2FN2VC.git diff --git a/n2vc/k8s_juju_conn.py b/n2vc/k8s_juju_conn.py index 149947d..2529480 100644 --- a/n2vc/k8s_juju_conn.py +++ b/n2vc/k8s_juju_conn.py @@ -13,6 +13,7 @@ # limitations under the License. import asyncio +from typing import Union import os import uuid import yaml @@ -20,6 +21,7 @@ import tempfile import binascii from n2vc.config import EnvironConfig +from n2vc.definitions import RelationEndpoint from n2vc.exceptions import K8sException from n2vc.k8s_conn import K8sConnector from n2vc.kubectl import Kubectl @@ -76,6 +78,7 @@ class K8sJujuConnector(K8sConnector): db_uri = EnvironConfig(prefixes=["OSMLCM_", "OSMMON_"]).get("database_uri") self._store = MotorStore(db_uri) self.loading_libjuju = asyncio.Lock(loop=self.loop) + self.uninstall_locks = {} self.log.debug("K8S Juju connector initialized") # TODO: Remove these commented lines: @@ -128,7 +131,7 @@ class K8sJujuConnector(K8sConnector): cleanup_data.append( { "delete": kubectl.delete_cluster_role, - "args": (metadata_name), + "args": (metadata_name,), } ) @@ -139,7 +142,7 @@ class K8sJujuConnector(K8sConnector): cleanup_data.append( { "delete": kubectl.delete_service_account, - "args": (metadata_name), + "args": (metadata_name,), } ) @@ -150,7 +153,7 @@ class K8sJujuConnector(K8sConnector): cleanup_data.append( { "delete": kubectl.delete_service_account, - "args": (metadata_name), + "args": (metadata_name,), } ) token, client_cert_data = await kubectl.get_secret_data( @@ -302,6 +305,10 @@ class K8sJujuConnector(K8sConnector): raise K8sException("bundle must be set") if bundle.startswith("cs:"): + # For Juju Bundles provided by the Charm Store + pass + elif bundle.startswith("ch:"): + # For Juju Bundles provided by the Charm Hub (this only works for juju version >= 2.9) pass elif bundle.startswith("http"): # Download the file @@ -491,18 +498,30 @@ class K8sJujuConnector(K8sConnector): """ self.log.debug("[uninstall] Destroying model") - libjuju = await self._get_libjuju(kwargs.get("vca_id")) - await libjuju.destroy_model(kdu_instance, total_timeout=3600) + will_not_delete = False + if kdu_instance not in self.uninstall_locks: + self.uninstall_locks[kdu_instance] = asyncio.Lock(loop=self.loop) + delete_lock = self.uninstall_locks[kdu_instance] + + while delete_lock.locked(): + will_not_delete = True + await asyncio.sleep(0.1) - # self.log.debug("[uninstall] Model destroyed and disconnecting") - # await controller.disconnect() + if will_not_delete: + self.log.info("Model {} deleted by another worker.".format(kdu_instance)) + return True + + try: + async with delete_lock: + libjuju = await self._get_libjuju(kwargs.get("vca_id")) + await libjuju.destroy_model(kdu_instance, total_timeout=3600) + finally: + self.uninstall_locks.pop(kdu_instance) + + self.log.debug(f"[uninstall] Model {kdu_instance} destroyed") return True - # TODO: Remove these commented lines - # if not self.authenticated: - # self.log.debug("[uninstall] Connecting to controller") - # await self.login(cluster_uuid) async def exec_primitive( self, @@ -641,7 +660,7 @@ class K8sJujuConnector(K8sConnector): complete_status: bool = False, yaml_format: bool = False, **kwargs, - ) -> dict: + ) -> Union[str, dict]: """Get the status of the KDU Get the current status of the KDU instance. @@ -673,6 +692,53 @@ class K8sJujuConnector(K8sConnector): return status + async def add_relation( + self, + provider: RelationEndpoint, + requirer: RelationEndpoint, + ): + """ + Add relation between two charmed endpoints + + :param: provider: Provider relation endpoint + :param: requirer: Requirer relation endpoint + """ + self.log.debug(f"adding new relation between {provider} and {requirer}") + cross_model_relation = ( + provider.model_name != requirer.model_name + or requirer.vca_id != requirer.vca_id + ) + try: + if cross_model_relation: + # Cross-model relation + provider_libjuju = await self._get_libjuju(provider.vca_id) + requirer_libjuju = await self._get_libjuju(requirer.vca_id) + offer = await provider_libjuju.offer(provider) + if offer: + saas_name = await requirer_libjuju.consume( + requirer.model_name, offer, provider_libjuju + ) + await requirer_libjuju.add_relation( + requirer.model_name, + requirer.endpoint, + saas_name, + ) + else: + # Standard relation + vca_id = provider.vca_id + model = provider.model_name + libjuju = await self._get_libjuju(vca_id) + # add juju relations between two applications + await libjuju.add_relation( + model_name=model, + endpoint_1=provider.endpoint, + endpoint_2=requirer.endpoint, + ) + except Exception as e: + message = f"Error adding relation between {provider} and {requirer}: {e}" + self.log.error(message) + raise Exception(message=message) + async def update_vca_status(self, vcastatus: dict, kdu_instance: str, **kwargs): """ Add all configs, actions, executed actions of all applications in a model to vcastatus dict