Bug 40 - Fix export of user created descriptors
[osm/SO.git] / rwlaunchpad / plugins / rwlaunchpadtasklet / rift / package / store.py
1
2 #
3 # Copyright 2016 RIFT.IO Inc
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 import os
19 import shutil
20
21 from . import package
22
23
24 class PackageStoreError(Exception):
25 pass
26
27
28 class PackageExistsError(PackageStoreError):
29 pass
30
31
32 class PackageNotFoundError(PackageStoreError):
33 pass
34
35
36 class PackageFilesystemStore(object):
37 """ This class is able to store/retreive/delete DescriptorPackages on disk
38
39 To insulate components from having to deal with accessing the filesystem directly
40 to deal with onboarded packages, this class provides a convenient interface for
41 storing, retreiving, deleting packages stored on disk. The interfaces deal directly
42 with DescriptorPackages so clients are abstracted from the actual location on disk.
43 """
44
45 def __init__(self, log, root_dir):
46 self._log = log
47 self._root_dir = root_dir
48 self._package_dirs = {}
49
50 self.refresh()
51
52 def _get_package_dir(self, package_id):
53 return os.path.join(self._root_dir, package_id)
54
55 def _get_package_files(self, package_id):
56 package_files = {}
57
58 package_dir = self._get_package_dir(package_id)
59
60 for dirpath, dirnames, filenames in os.walk(package_dir):
61 for name in filenames:
62 file_path = os.path.join(dirpath, name)
63 file_rel_path = os.path.relpath(file_path, package_dir)
64 package_files[file_rel_path] = file_path
65
66 return package_files
67
68 def refresh(self):
69 """ Refresh the package index from disk """
70 if not os.path.exists(self._root_dir):
71 self._package_dirs = {}
72 return
73
74 package_dirs = {}
75 for package_id_dir in os.listdir(self._root_dir):
76 try:
77 package_dir_path = os.path.join(self._root_dir, package_id_dir)
78 if not os.path.isdir(package_dir_path):
79 self._log.warning("Unknown file in package store: %s", package_dir_path)
80 continue
81
82 files = os.listdir(package_dir_path)
83 if len(files) == 0:
84 self._log.warning("Package directory %s is empty", package_dir_path)
85 continue
86
87 package_id = os.path.basename(package_id_dir)
88 package_dirs[package_id] = package_id_dir
89
90 except OSError as e:
91 self._log.warning("Failed to read packages from %s: %s",
92 package_dir_path, str(e))
93
94 self._package_dirs = package_dirs
95
96 def get_package(self, package_id):
97 """ Get a DescriptorPackage on disk from the package descriptor id
98
99 Arguments:
100 package_id - The DescriptorPackage.descriptor_id
101
102 Returns:
103 A DescriptorPackage instance of the correct type
104
105 Raises:
106 PackageStoreError- The package could not be retrieved
107 """
108 if package_id not in self._package_dirs:
109 msg = "Package %s not found in %s" % (package_id, self._root_dir)
110 raise PackageNotFoundError(msg)
111
112 package_files = self._get_package_files(package_id)
113 package_dir = self._get_package_dir(package_id)
114
115 def do_open(pkg_file):
116 pkg_path = os.path.join(package_dir, pkg_file)
117 return open(pkg_path, "rb")
118
119 pkg = package.DescriptorPackage.from_package_files(self._log, do_open, package_files)
120 for pkg_file in package_files:
121 pkg.add_file(pkg_file)
122
123 return pkg
124
125 def store_package(self, pkg):
126 """ Store a DescriptorPackage to disk
127
128 Arguments:
129 pkg - A DescriptorPackage
130
131 Raises:
132 PackageStoreError - The package could not be stored
133 """
134 if pkg.descriptor_id in self._package_dirs:
135 raise PackageExistsError("Package %s already exists", pkg.descriptor_id)
136
137 package_dir = self._get_package_dir(pkg.descriptor_id)
138
139 try:
140 os.makedirs(package_dir, exist_ok=True)
141 except OSError as e:
142 raise PackageStoreError("Failed to create package dir: %s", package_dir) from e
143
144 try:
145 self._log.debug("Storing package in dir %s", package_dir)
146 pkg.extract(package_dir)
147 self._log.debug("Package stored in dir %s", package_dir)
148 except pkg.PackageError as e:
149 raise PackageStoreError("Failed to extract package to package store") from e
150
151 self._package_dirs[pkg.descriptor_id] = package_dir
152
153 def delete_package(self, descriptor_id):
154 """ Delete a stored DescriptorPackage
155
156 Arguments:
157 descriptor_id - The DescriptorPackage.descriptor_id
158
159 Raises:
160 PackageNotFoundError - The package could not be found
161 PackageStoreError - The package could not be deleted
162 """
163
164 if descriptor_id not in self._package_dirs:
165 raise PackageNotFoundError("Package %s does not exists", descriptor_id)
166
167 package_dir = self._get_package_dir(descriptor_id)
168 try:
169 if os.path.exists(package_dir):
170 self._log.debug("Removing stored package directory: %s", package_dir)
171 shutil.rmtree(package_dir)
172 except OSError as e:
173 raise PackageStoreError(
174 "Failed to remove stored package directory: %s", package_dir
175 ) from e
176
177 del self._package_dirs[descriptor_id]
178
179 def update_package(self, pkg):
180 """ Update a stored DescriptorPackage
181
182 Arguments:
183 pkg - A DescriptorPackage
184
185 Raises:
186 PackageNotFoundError - The package could not be found
187 PackageStoreError - The package could not be deleted
188 """
189 self.delete_package(pkg.descriptor_id)
190 self.store_package(pkg)
191
192
193 class NsdPackageFilesystemStore(PackageFilesystemStore):
194 DEFAULT_ROOT_DIR = os.path.join(
195 os.environ["RIFT_ARTIFACTS"],
196 "launchpad", "packages", "nsd"
197 )
198
199 def __init__(self, log, root_dir=DEFAULT_ROOT_DIR):
200 super().__init__(log, root_dir)
201
202
203 class VnfdPackageFilesystemStore(PackageFilesystemStore):
204 DEFAULT_ROOT_DIR = os.path.join(
205 os.environ["RIFT_ARTIFACTS"],
206 "launchpad", "packages", "vnfd"
207 )
208
209 def __init__(self, log, root_dir=DEFAULT_ROOT_DIR):
210 super().__init__(log, root_dir)
211