##
import asyncio
+import checksumdir
from collections import OrderedDict
+import os
+import shutil
+import traceback
from time import time
+
+from osm_common.fsbase import FsException
from osm_lcm.data_utils.database.database import Database
from osm_lcm.data_utils.filesystem.filesystem import Filesystem
+import yaml
+from zipfile import ZipFile, BadZipfile
# from osm_common.dbbase import DbException
return in_dict[in_key]
+def check_juju_bundle_existence(vnfd: dict) -> str:
+ """Checks the existence of juju-bundle in the descriptor
+
+ Args:
+ vnfd: Descriptor as a dictionary
+
+ Returns:
+ Juju bundle if dictionary has juju-bundle else None
+
+ """
+ if vnfd.get("vnfd"):
+ vnfd = vnfd["vnfd"]
+
+ for kdu in vnfd.get("kdu", []):
+ return kdu.get("juju-bundle", None)
+
+
+def get_charm_artifact_path(base_folder, charm_name, charm_type, revision=str()) -> str:
+ """Finds the charm artifact paths
+
+ Args:
+ base_folder: Main folder which will be looked up for charm
+ charm_name: Charm name
+ charm_type: Type of charm native_charm, lxc_proxy_charm or k8s_proxy_charm
+ revision: vnf package revision number if there is
+
+ Returns:
+ artifact_path: (str)
+
+ """
+ extension = ""
+ if revision:
+ extension = ":" + str(revision)
+
+ if base_folder.get("pkg-dir"):
+ artifact_path = "{}/{}/{}/{}".format(
+ base_folder["folder"].split(":")[0] + extension,
+ base_folder["pkg-dir"],
+ "charms"
+ if charm_type in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
+ else "helm-charts",
+ charm_name,
+ )
+
+ else:
+ # For SOL004 packages
+ artifact_path = "{}/Scripts/{}/{}".format(
+ base_folder["folder"].split(":")[0] + extension,
+ "charms"
+ if charm_type in ("native_charm", "lxc_proxy_charm", "k8s_proxy_charm")
+ else "helm-charts",
+ charm_name,
+ )
+
+ return artifact_path
+
+
def populate_dict(target_dict, key_list, value):
"""
Update target_dict creating nested dictionaries with the key_list. Last key_list item is asigned the value.
target_dict[key_list[-1]] = value
+def get_ee_id_parts(ee_id):
+ """
+ Parses ee_id stored at database that can be either 'version:namespace.helm_id' or only
+ namespace.helm_id for backward compatibility
+ If exists helm version can be helm-v3 or helm (helm-v2 old version)
+ """
+ version, _, part_id = ee_id.rpartition(":")
+ namespace, _, helm_id = part_id.rpartition(".")
+ return version, namespace, helm_id
+
+
class LcmBase:
def __init__(self, msg, logger):
"""
def update_db_2(self, item, _id, _desc):
"""
Updates database with _desc information. If success _desc is cleared
- :param item:
- :param _id:
+ :param item: collection
+ :param _id: the _id to use in the query filter
:param _desc: dictionary with the content to update. Keys are dot separated keys for
:return: None. Exception is raised on error
"""
# except DbException as e:
# self.logger.error("Updating {} _id={} with '{}'. Error: {}".format(item, _id, _desc, e))
+ def check_charm_hash_changed(
+ self, current_charm_path: str, target_charm_path: str
+ ) -> bool:
+ """Find the target charm has changed or not by checking the hash of
+ old and new charm packages
+
+ Args:
+ current_charm_path (str): Existing charm package artifact path
+ target_charm_path (str): Target charm package artifact path
+
+ Returns:
+ True/False (bool): if charm has changed it returns True
+
+ """
+ # Check if the charm artifacts are available
+ if os.path.exists(self.fs.path + current_charm_path) and os.path.exists(
+ self.fs.path + target_charm_path
+ ):
+ # Compare the hash of charm folders
+ if checksumdir.dirhash(
+ self.fs.path + current_charm_path
+ ) != checksumdir.dirhash(self.fs.path + target_charm_path):
+
+ return True
+
+ return False
+
+ else:
+ raise LcmException(
+ "Charm artifact {} does not exist in the VNF Package".format(
+ self.fs.path + target_charm_path
+ )
+ )
+
+ @staticmethod
+ def get_charm_name(charm_metadata_file: str) -> str:
+ """Get the charm name from metadata file.
+
+ Args:
+ charm_metadata_file (str): charm metadata file full path
+
+ Returns:
+ charm_name (str): charm name
+
+ """
+ # Read charm metadata.yaml to get the charm name
+ with open(charm_metadata_file, "r") as metadata_file:
+ content = yaml.safe_load(metadata_file)
+ charm_name = content["name"]
+ return str(charm_name)
+
+ def _get_charm_path(
+ self, nsd_package_path: str, nsd_package_name: str, charm_folder_name: str
+ ) -> str:
+ """Get the full path of charm folder.
+
+ Args:
+ nsd_package_path (str): NSD package full path
+ nsd_package_name (str): NSD package name
+ charm_folder_name (str): folder name
+
+ Returns:
+ charm_path (str): charm folder full path
+ """
+ charm_path = (
+ self.fs.path
+ + nsd_package_path
+ + "/"
+ + nsd_package_name
+ + "/charms/"
+ + charm_folder_name
+ )
+ return charm_path
+
+ def _get_charm_metadata_file(
+ self,
+ charm_folder_name: str,
+ nsd_package_path: str,
+ nsd_package_name: str,
+ charm_path: str = None,
+ ) -> str:
+ """Get the path of charm metadata file.
+
+ Args:
+ charm_folder_name (str): folder name
+ nsd_package_path (str): NSD package full path
+ nsd_package_name (str): NSD package name
+ charm_path (str): Charm full path
+
+ Returns:
+ charm_metadata_file_path (str): charm metadata file full path
+
+ """
+ # Locate the charm metadata.yaml
+ if charm_folder_name.endswith(".charm"):
+ extract_path = (
+ self.fs.path
+ + nsd_package_path
+ + "/"
+ + nsd_package_name
+ + "/charms/"
+ + charm_folder_name.replace(".charm", "")
+ )
+ # Extract .charm to extract path
+ with ZipFile(charm_path, "r") as zipfile:
+ zipfile.extractall(extract_path)
+ return extract_path + "/metadata.yaml"
+ else:
+ return charm_path + "/metadata.yaml"
+
+ def find_charm_name(self, db_nsr: dict, charm_folder_name: str) -> str:
+ """Get the charm name from metadata.yaml of charm package.
+
+ Args:
+ db_nsr (dict): NS record as a dictionary
+ charm_folder_name (str): charm folder name
+
+ Returns:
+ charm_name (str): charm name
+ """
+ try:
+ if not charm_folder_name:
+ raise LcmException("charm_folder_name should be provided.")
+
+ # Find nsd_package details: path, name
+ revision = db_nsr.get("revision", "")
+
+ # Get the NSD package path
+ if revision:
+
+ nsd_package_path = db_nsr["nsd-id"] + ":" + str(revision)
+ db_nsd = self.db.get_one("nsds_revisions", {"_id": nsd_package_path})
+
+ else:
+ nsd_package_path = db_nsr["nsd-id"]
+
+ db_nsd = self.db.get_one("nsds", {"_id": nsd_package_path})
+
+ # Get the NSD package name
+ nsd_package_name = db_nsd["_admin"]["storage"]["pkg-dir"]
+
+ # Remove the existing nsd package and sync from FsMongo
+ shutil.rmtree(self.fs.path + nsd_package_path, ignore_errors=True)
+ self.fs.sync(from_path=nsd_package_path)
+
+ # Get the charm path
+ charm_path = self._get_charm_path(
+ nsd_package_path, nsd_package_name, charm_folder_name
+ )
+
+ # Find charm metadata file full path
+ charm_metadata_file = self._get_charm_metadata_file(
+ charm_folder_name, nsd_package_path, nsd_package_name, charm_path
+ )
+
+ # Return charm name
+ return self.get_charm_name(charm_metadata_file)
+
+ except (
+ yaml.YAMLError,
+ IOError,
+ FsException,
+ KeyError,
+ TypeError,
+ FileNotFoundError,
+ BadZipfile,
+ ) as error:
+ self.logger.debug(traceback.format_exc())
+ self.logger.error(f"{error} occured while getting the charm name")
+ raise LcmException(error)
+
class TaskRegistry(LcmBase):
"""