-#
+#
# Copyright 2016 RIFT.IO Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
pass
+class PackageAppendError(Exception):
+ pass
+
+
class PackageFileChecksumError(PackageValidationError):
def __init__(self, filename):
self.filename = filename
return self.descriptor_msg.id
+ @property
+ def descriptor_name(self):
+ """ The descriptor name of this descriptor in the system """
+ if not self.descriptor_msg.has_field("name"):
+ msg = "Descriptor name not present"
+ self._log.error(msg)
+ raise PackageError(msg)
+
+ return self.descriptor_msg.name
+
+ @property
+ def descriptor_version(self):
+ desc_msg = self.descriptor_msg
+ return desc_msg.version if desc_msg.has_field("version") else ''
+
+ @property
+ def descriptor_vendor(self):
+ desc_msg = self.descriptor_msg
+ return desc_msg.vendor if desc_msg.has_field("vendor") else ''
+
@classmethod
def get_descriptor_patterns(cls):
""" Returns a tuple of descriptor regex and Package Types """
continue
# Copy the contents of the file to the correct path
- dest_file_path = os.path.join(dest_root_dir, filename)
+ # Remove the common prefix and create the dest filename
+ if src_dir is not None:
+ fname = filename[len(src_dir):]
+ if fname[0] == '/':
+ fname = fname[1:]
+ else:
+ fname = filename
+ dest_file_path = os.path.join(dest_root_dir, fname)
dest_dir_path = os.path.dirname(dest_file_path)
if not os.path.exists(dest_dir_path):
os.makedirs(dest_dir_path)
# Set the file mode to original
os.chmod(dest_file_path, self._package_file_mode_map[filename])
+ def insert_file(self, new_file, dest_file, rel_path, mode=0o777):
+ self.add_file(rel_path, mode)
+
+ try:
+ # Copy the contents of the file to the correct path
+ # For folder creation (or nested folders), dest_file appears w/ trailing "/" like: dir1/ or dir1/dir2/
+ # For regular file upload, dest_file appears as dir1/abc.txt
+
+ dest_dir_path = os.path.dirname(dest_file)
+ if not os.path.isdir(dest_dir_path):
+ os.makedirs(dest_dir_path)
+ if not os.path.basename(dest_file):
+ self._log.debug("Created dir path, no filename to insert in {}, skipping..".format(dest_dir_path))
+ return
+
+ with open(dest_file, 'wb') as dst_hdl:
+ with open(new_file, 'rb') as src_hdl:
+ shutil.copyfileobj(src_hdl, dst_hdl, 10 * 1024 * 1024)
+
+ # Set the file mode to original
+ os.chmod(dest_file, self._package_file_mode_map[rel_path])
+ except Exception as e:
+ # Clear the file when an exception happens
+ if os.path.isfile(dest_file):
+ os.remove(dest_file)
+
+ raise PackageAppendError(str(e))
+
+ def delete_file(self, dest_file, rel_path):
+ self.remove_file(rel_path)
+
+ try:
+ os.remove(dest_file)
+ except Exception as e:
+ raise PackageAppendError(str(e))
+
def extract_file(self, src_file, dest_file):
""" Extract a specific package file to dest_file
Raises:
NotADirectoryError - dest_root_dir is not a directory
"""
+ def find_prefix():
+ """ Find comon prefix of all files in package. This prefix will be
+ used to collapse directory structure during extraction to eliminate
+ empty nested folders.
+ """
+ common_dir = set()
+ for f in self.files:
+ common_dir.add(os.path.dirname(f))
+ prefix = os.path.commonprefix(list(common_dir))
+ return prefix if prefix else None
+
if not os.path.isdir(dest_root_dir):
raise NotADirectoryError(dest_root_dir)
- self.extract_dir(None, dest_root_dir, extract_images)
+ self.extract_dir(find_prefix(), dest_root_dir, extract_images)
def open(self, rel_path):
""" Open a file contained in the package in read-only, binary mode.
self._package_file_mode_map[rel_path] = mode
+ def remove_file(self, rel_path):
+ if not rel_path:
+ raise PackageError("Empty file name added")
+
+ if rel_path not in self._package_file_mode_map:
+ raise PackageError("File %s does not exist in package" % rel_path)
+
+ del self._package_file_mode_map[rel_path]
+
def add_dir(self, rel_path):
""" Add a directory to the package
def serializer(self):
return VnfdPackage.SERIALIZER
+class PackageConstructValidator(object):
+
+ def __init__(self, log):
+ self._log = log
+
+ def validate(self, package):
+ """ Validate presence of descriptor file (.yaml) at the top level in the
+ package folder structure.
+
+ Arguments:
+ package - The Descriptor Package being validated.
+ Returns:
+ None
+ Raises:
+ PackageValidationError - The package validation failed for some
+ generic reason.
+ """
+ pass
+ desc_file = package.descriptor_file
+ prefix, desc_file = package.prefix.rstrip('/'), desc_file.rstrip('/')
+
+ if os.path.dirname(desc_file) != prefix:
+ msg = "Descriptor file {} not found in expcted location {}".format(desc_file, prefix)
+ self._log.error(msg)
+ raise PackageValidationError(msg)
+
class PackageChecksumValidator(object):
""" This class uses the checksums.txt file in the package
def __init__(self, log):
self._log = log
+ self.validated_file_checksums = {}
@classmethod
def get_package_checksum_file(cls, package):
return checksum_file
+ @property
+ def checksums(self):
+ return self.validated_file_checksums
+
def validate(self, package):
""" Validate file checksums match that in the checksums.txt
PackageFileChecksumError - A file within the package did not match the
checksum within checksums.txt
"""
- validated_file_checksums = {}
try:
checksum_file = PackageChecksumValidator.get_package_checksum_file(package)
archive_checksums = checksums.ArchiveChecksums.from_file_desc(checksum_hdl)
except (FileNotFoundError, PackageError) as e:
self._log.warning("Could not open package checksum file. Not validating checksums.")
- return validated_file_checksums
+ return self.validated_file_checksums
for pkg_file in package.files:
if pkg_file == checksum_file:
raise PackageValidationError(msg) from e
if archive_checksums[pkg_file_no_prefix] != file_checksum:
- msg = "{} checksum ({}) did match expected checksum ({})".format(
+ msg = "{} checksum ({}) did not match expected checksum ({})".format(
pkg_file, file_checksum, archive_checksums[pkg_file_no_prefix]
)
self._log.error(msg)
raise PackageFileChecksumError(pkg_file)
- validated_file_checksums[pkg_file] = file_checksum
-
- return validated_file_checksums
+ self.validated_file_checksums[pkg_file] = file_checksum
class TarPackageArchive(object):