X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FN2VC.git;a=blobdiff_plain;f=n2vc%2Fn2vc_juju_conn.py;h=fb368096413d306c0a13ea9cd0d2f17242994695;hp=55220d64ab389f178fd4ac13dea63a5809f88b49;hb=cd986064a281ab1658023fa7172a57612f270684;hpb=582b923b8f3f7104411c39ebdba63949d606ecd1 diff --git a/n2vc/n2vc_juju_conn.py b/n2vc/n2vc_juju_conn.py index 55220d6..fb36809 100644 --- a/n2vc/n2vc_juju_conn.py +++ b/n2vc/n2vc_juju_conn.py @@ -39,7 +39,7 @@ from n2vc.n2vc_conn import N2VCConnector from n2vc.n2vc_conn import obj_to_dict, obj_to_yaml from n2vc.libjuju import Libjuju from n2vc.store import MotorStore -from n2vc.utils import get_ee_id_components +from n2vc.utils import get_ee_id_components, generate_random_alfanum_string from n2vc.vca.connection import get_connection from retrying_async import retry @@ -93,7 +93,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.delete_namespace_locks = {} self.log.info("N2VC juju connector initialized") async def get_status( @@ -791,33 +791,56 @@ class N2VCJujuConnector(N2VCConnector): :param: vca_id: VCA ID """ self.log.info("Deleting namespace={}".format(namespace)) - libjuju = await self._get_libjuju(vca_id) + will_not_delete = False + if namespace not in self.delete_namespace_locks: + self.delete_namespace_locks[namespace] = asyncio.Lock(loop=self.loop) + delete_lock = self.delete_namespace_locks[namespace] - # check arguments - if namespace is None: - raise N2VCBadArgumentsException( - message="namespace is mandatory", bad_args=["namespace"] - ) + while delete_lock.locked(): + will_not_delete = True + await asyncio.sleep(0.1) - _nsi_id, ns_id, _vnf_id, _vdu_id, _vdu_count = self._get_namespace_components( - namespace=namespace - ) - if ns_id is not None: - try: - models = await libjuju.list_models(contains=ns_id) - for model in models: - await libjuju.destroy_model( - model_name=model, total_timeout=total_timeout + if will_not_delete: + self.log.info("Namespace {} deleted by another worker.".format(namespace)) + return + + try: + async with delete_lock: + libjuju = await self._get_libjuju(vca_id) + + # check arguments + if namespace is None: + raise N2VCBadArgumentsException( + message="namespace is mandatory", bad_args=["namespace"] ) - except Exception as e: - raise N2VCException( - message="Error deleting namespace {} : {}".format(namespace, e) - ) - else: - raise N2VCBadArgumentsException( - message="only ns_id is permitted to delete yet", bad_args=["namespace"] - ) + ( + _nsi_id, + ns_id, + _vnf_id, + _vdu_id, + _vdu_count, + ) = self._get_namespace_components(namespace=namespace) + if ns_id is not None: + try: + models = await libjuju.list_models(contains=ns_id) + for model in models: + await libjuju.destroy_model( + model_name=model, total_timeout=total_timeout + ) + except Exception as e: + raise N2VCException( + message="Error deleting namespace {} : {}".format( + namespace, e + ) + ) + else: + raise N2VCBadArgumentsException( + message="only ns_id is permitted to delete yet", + bad_args=["namespace"], + ) + finally: + self.delete_namespace_locks.pop(namespace) self.log.info("Namespace {} deleted".format(namespace)) async def delete_execution_environment( @@ -1140,7 +1163,7 @@ class N2VCJujuConnector(N2VCConnector): """ Build application name from namespace :param namespace: - :return: app-vnf--vdu--cnt- + :return: app-vnf--vdu--cnt-- """ # TODO: Enforce the Juju 50-character application limit @@ -1167,7 +1190,12 @@ class N2VCJujuConnector(N2VCConnector): else: vdu_count = "-cnt-" + vdu_count - application_name = "app-{}{}{}".format(vnf_id, vdu_id, vdu_count) + # Generate a random suffix with 5 characters (the default size used by K8s) + random_suffix = generate_random_alfanum_string(size=5) + + application_name = "app-{}{}{}-{}".format( + vnf_id, vdu_id, vdu_count, random_suffix + ) return N2VCJujuConnector._format_app_name(application_name)