--- /dev/null
+
+#
+# Copyright 2016 RIFT.IO Inc
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import collections
+import io
+import os
+import shutil
+import tarfile
+import tempfile
+import tornado.httputil
+
+import rift.package.package
+import rift.package.convert
+import rift.package.image
+import rift.package.checksums
+
+from .convert_pkg import ConvertPackage
+
+
+class ExtractError(Exception):
+ pass
+
+
+class UnreadableHeadersError(ExtractError):
+ pass
+
+
+class MissingTerminalBoundary(ExtractError):
+ pass
+
+
+class UnreadableDescriptorError(ExtractError):
+ pass
+
+
+class UnreadablePackageError(ExtractError):
+ pass
+
+
+class PackageImage(object):
+ def __init__(self, log, image_name, image_hdl, checksum=None):
+ self.name = image_name
+ self.image_hdl = image_hdl
+
+ if checksum is None:
+ log.debug("Image %s checksum not provided, calculating checksum...")
+ checksum = rift.package.checksums.checksum(self.image_hdl)
+ log.debug("Image %s checksum: %s", self.name, checksum)
+
+ self.checksum = checksum
+
+
+class UploadPackageExtractor(object):
+ def __init__(self, log):
+ self._log = log
+
+ def create_packages_from_upload(self, uploaded_file, extracted_pkgfile):
+ def create_package_from_descriptor_file(desc_hdl):
+ # Uploaded package was a plain descriptor file
+ bytes_hdl = io.BytesIO(desc_hdl.read())
+ bytes_hdl.name = uploaded_file
+ try:
+ package = rift.package.package.DescriptorPackage.from_descriptor_file_hdl(
+ self._log, bytes_hdl
+ )
+ except rift.package.package.PackageError as e:
+ msg = "Could not create descriptor package from descriptor: %s" % str(e)
+ self._log.error(msg)
+ raise UnreadableDescriptorError(msg) from e
+
+ return package
+
+ def create_package_from_tar_file(tar_hdl):
+ # Uploaded package was in a .tar.gz format
+ tar_archive = rift.package.package.TarPackageArchive(
+ self._log, tar_hdl,
+ )
+ try:
+ package = tar_archive.create_package()
+ except rift.package.package.PackageError as e:
+ msg = "Could not create package from tar archive: %s" % str(e)
+ self._log.error(msg)
+ raise UnreadablePackageError(msg) from e
+
+ return package
+
+ self._log.info("creating package from uploaded descriptor file/package")
+ tmp_pkgs = []
+ upload_hdl = None
+ try:
+ # This file handle will be passed to TemporaryPackage to be closed
+ # and the underlying file removed.
+ upload_hdl = open(extracted_pkgfile, "r+b")
+
+ # Process the package archive
+ if tarfile.is_tarfile(extracted_pkgfile):
+ package = create_package_from_tar_file(upload_hdl)
+ tmp_pkgs.append(rift.package.package.TemporaryPackage(self._log,
+ package,
+ upload_hdl))
+
+ # Check if this is just a descriptor file
+ elif rift.package.convert.ProtoMessageSerializer.is_supported_file(uploaded_file):
+ package = create_package_from_descriptor_file(upload_hdl)
+ tmp_pkgs.append(rift.package.package.TemporaryPackage(self._log,
+ package,
+ upload_hdl))
+
+ else:
+ # See if the pacakage can be converted
+ files = ConvertPackage(self._log,
+ uploaded_file,
+ extracted_pkgfile).convert(delete=True)
+
+ if files is None or not len(files):
+ # Not converted successfully
+ msg = "Uploaded file was neither a tar.gz or descriptor file"
+ self._log.error(msg)
+ raise UnreadablePackageError(msg)
+
+ # Close the open file handle as this file is not used anymore
+ upload_hdl.close()
+
+ for f in files:
+ self._log.debug("Upload converted file: {}".format(f))
+ upload_hdl = open(f, "r+b")
+ package = create_package_from_tar_file(upload_hdl)
+ tmp_pkgs.append(rift.package.package.TemporaryPackage(self._log,
+ package,
+ upload_hdl))
+
+ except Exception as e:
+ # Cleanup any TemporaryPackage instances created
+ for t in tmp_pkgs:
+ t.close()
+
+ # Close the handle if not already closed
+ try:
+ if upload_hdl is not None:
+ upload_hdl.close()
+ except OSError as e:
+ self._log.warning("Failed to close file handle: %s", str(e))
+
+ try:
+ self._log.debug("Removing extracted package file: %s", extracted_pkgfile)
+ os.remove(extracted_pkgfile)
+ except OSError as e:
+ self._log.warning("Failed to remove extracted package dir: %s", str(e))
+
+ raise e
+
+ return tmp_pkgs