RIFT OSM R1 Initial Submission
[osm/SO.git] / rwlaunchpad / plugins / rwlaunchpadtasklet / rift / package / store.py
diff --git a/rwlaunchpad/plugins/rwlaunchpadtasklet/rift/package/store.py b/rwlaunchpad/plugins/rwlaunchpadtasklet/rift/package/store.py
new file mode 100644 (file)
index 0000000..454546d
--- /dev/null
@@ -0,0 +1,211 @@
+
+# 
+#   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 os
+import shutil
+
+from . import package
+
+
+class PackageStoreError(Exception):
+    pass
+
+
+class PackageExistsError(PackageStoreError):
+    pass
+
+
+class PackageNotFoundError(PackageStoreError):
+    pass
+
+
+class PackageFilesystemStore(object):
+    """ This class is able to store/retreive/delete DescriptorPackages on disk
+
+    To insulate components from having to deal with accessing the filesystem directly
+    to deal with onboarded packages, this class provides a convenient interface for
+    storing, retreiving, deleting packages stored on disk.  The interfaces deal directly
+    with DescriptorPackages so clients are abstracted from the actual location on disk.
+    """
+
+    def __init__(self, log, root_dir):
+        self._log = log
+        self._root_dir = root_dir
+        self._package_dirs = {}
+
+        self.refresh()
+
+    def _get_package_dir(self, package_id):
+        return os.path.join(self._root_dir, package_id)
+
+    def _get_package_files(self, package_id):
+        package_files = {}
+
+        package_dir = self._get_package_dir(package_id)
+
+        for dirpath, dirnames, filenames in os.walk(package_dir):
+            for name in filenames:
+                file_path = os.path.join(dirpath, name)
+                file_rel_path = os.path.relpath(file_path, package_dir)
+                package_files[file_rel_path] = file_path
+
+        return package_files
+
+    def refresh(self):
+        """ Refresh the package index from disk  """
+        if not os.path.exists(self._root_dir):
+            self._package_dirs = {}
+            return
+
+        package_dirs = {}
+        for package_id_dir in os.listdir(self._root_dir):
+            try:
+                package_dir_path = os.path.join(self._root_dir, package_id_dir)
+                if not os.path.isdir(package_dir_path):
+                    self._log.warning("Unknown file in package store: %s", package_dir_path)
+                    continue
+
+                files = os.listdir(package_dir_path)
+                if len(files) == 0:
+                    self._log.warning("Package directory %s is empty", package_dir_path)
+                    continue
+
+                package_id = os.path.basename(package_id_dir)
+                package_dirs[package_id] = package_id_dir
+
+            except OSError as e:
+                self._log.warning("Failed to read packages from %s: %s",
+                                  package_dir_path, str(e))
+
+        self._package_dirs = package_dirs
+
+    def get_package(self, package_id):
+        """ Get a DescriptorPackage on disk from the package descriptor id
+
+        Arguments:
+            package_id - The DescriptorPackage.descriptor_id
+
+        Returns:
+            A DescriptorPackage instance of the correct type
+
+        Raises:
+            PackageStoreError- The package could not be retrieved
+        """
+        if package_id not in self._package_dirs:
+            msg = "Package %s not found in %s" % (package_id, self._root_dir)
+            raise PackageStoreError(msg)
+
+        package_files = self._get_package_files(package_id)
+        package_dir = self._get_package_dir(package_id)
+
+        def do_open(pkg_file):
+            pkg_path = os.path.join(package_dir, pkg_file)
+            return open(pkg_path, "rb")
+
+        pkg = package.DescriptorPackage.from_package_files(self._log, do_open, package_files)
+        for pkg_file in package_files:
+            pkg.add_file(pkg_file)
+
+        return pkg
+
+    def store_package(self, pkg):
+        """ Store a DescriptorPackage to disk
+
+        Arguments:
+            pkg - A DescriptorPackage
+
+        Raises:
+            PackageStoreError - The package could not be stored
+        """
+        if pkg.descriptor_id in self._package_dirs:
+            raise PackageExistsError("Package %s already exists", pkg.descriptor_id)
+
+        package_dir = self._get_package_dir(pkg.descriptor_id)
+
+        try:
+            os.makedirs(package_dir, exist_ok=True)
+        except OSError as e:
+            raise PackageStoreError("Failed to create package dir: %s", package_dir) from e
+
+        try:
+            self._log.debug("Storing package in dir %s", package_dir)
+            pkg.extract(package_dir)
+            self._log.debug("Package stored in dir %s", package_dir)
+        except pkg.PackageError as e:
+            raise PackageStoreError("Failed to extract package to package store") from e
+
+        self._package_dirs[pkg.descriptor_id] = package_dir
+
+    def delete_package(self, descriptor_id):
+        """ Delete a stored DescriptorPackage
+
+        Arguments:
+            descriptor_id - The DescriptorPackage.descriptor_id
+
+        Raises:
+            PackageNotFoundError - The package could not be found
+            PackageStoreError - The package could not be deleted
+        """
+
+        if descriptor_id not in self._package_dirs:
+            raise PackageNotFoundError("Package %s does not exists", descriptor_id)
+
+        package_dir = self._get_package_dir(descriptor_id)
+        try:
+            if os.path.exists(package_dir):
+                self._log.debug("Removing stored package directory: %s", package_dir)
+                shutil.rmtree(package_dir)
+        except OSError as e:
+            raise PackageStoreError(
+                    "Failed to remove stored package directory: %s", package_dir
+                    ) from e
+
+        del self._package_dirs[descriptor_id]
+
+    def update_package(self, pkg):
+        """ Update a stored DescriptorPackage
+
+        Arguments:
+            pkg - A DescriptorPackage
+
+        Raises:
+            PackageNotFoundError - The package could not be found
+            PackageStoreError - The package could not be deleted
+        """
+        self.delete_package(pkg.descriptor_id)
+        self.store_package(pkg)
+
+
+class NsdPackageFilesystemStore(PackageFilesystemStore):
+    DEFAULT_ROOT_DIR = os.path.join(
+            os.environ["RIFT_ARTIFACTS"],
+            "launchpad", "packages", "nsd"
+            )
+
+    def __init__(self, log, root_dir=DEFAULT_ROOT_DIR):
+        super().__init__(log, root_dir)
+
+
+class VnfdPackageFilesystemStore(PackageFilesystemStore):
+    DEFAULT_ROOT_DIR = os.path.join(
+            os.environ["RIFT_ARTIFACTS"],
+            "launchpad", "packages", "vnfd"
+            )
+
+    def __init__(self, log, root_dir=DEFAULT_ROOT_DIR):
+        super().__init__(log, root_dir)
+