34fff1cde45ce3f84d50d4fc3490d56757758b06
[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 @property
53 def root_dir(self):
54 return self._root_dir
55
56
57 def _get_package_dir(self, package_id):
58 return os.path.join(self._root_dir, package_id)
59
60 def _get_package_files(self, package_id):
61 package_files = {}
62
63 package_dir = self._get_package_dir(package_id)
64
65 for dirpath, dirnames, filenames in os.walk(package_dir):
66 for name in filenames:
67 file_path = os.path.join(dirpath, name)
68 file_rel_path = os.path.relpath(file_path, package_dir)
69 package_files[file_rel_path] = file_path
70
71 return package_files
72
73 def refresh(self):
74 """ Refresh the package index from disk """
75 if not os.path.exists(self._root_dir):
76 self._package_dirs = {}
77 return
78
79 package_dirs = {}
80 for package_id_dir in os.listdir(self._root_dir):
81 try:
82 package_dir_path = os.path.join(self._root_dir, package_id_dir)
83 if not os.path.isdir(package_dir_path):
84 self._log.warning("Unknown file in package store: %s", package_dir_path)
85 continue
86
87 files = os.listdir(package_dir_path)
88 if len(files) == 0:
89 self._log.warning("Package directory %s is empty", package_dir_path)
90 continue
91
92 package_id = os.path.basename(package_id_dir)
93 package_dirs[package_id] = package_id_dir
94
95 except OSError as e:
96 self._log.warning("Failed to read packages from %s: %s",
97 package_dir_path, str(e))
98
99 self._package_dirs = package_dirs
100
101 def get_package(self, package_id):
102 """ Get a DescriptorPackage on disk from the package descriptor id
103
104 Arguments:
105 package_id - The DescriptorPackage.descriptor_id
106
107 Returns:
108 A DescriptorPackage instance of the correct type
109
110 Raises:
111 PackageStoreError- The package could not be retrieved
112 """
113 if package_id not in self._package_dirs:
114 msg = "Package %s not found in %s" % (package_id, self._root_dir)
115 raise PackageNotFoundError(msg)
116
117 package_files = self._get_package_files(package_id)
118 package_dir = self._get_package_dir(package_id)
119
120 def do_open(pkg_file):
121 pkg_path = os.path.join(package_dir, pkg_file)
122 return open(pkg_path, "rb")
123
124 pkg = package.DescriptorPackage.from_package_files(self._log, do_open, package_files)
125 for pkg_file in package_files:
126 pkg.add_file(pkg_file)
127
128 return pkg
129
130 def store_package(self, pkg):
131 """ Store a DescriptorPackage to disk
132
133 Arguments:
134 pkg - A DescriptorPackage
135
136 Raises:
137 PackageStoreError - The package could not be stored
138 """
139 if pkg.descriptor_id in self._package_dirs:
140 raise PackageExistsError("Package %s already exists", pkg.descriptor_id)
141
142 package_dir = self._get_package_dir(pkg.descriptor_id)
143
144 try:
145 os.makedirs(package_dir, exist_ok=True)
146 except OSError as e:
147 raise PackageStoreError("Failed to create package dir: %s", package_dir) from e
148
149 try:
150 self._log.debug("Storing package in dir %s", package_dir)
151 pkg.extract(package_dir)
152 self._log.debug("Package stored in dir %s", package_dir)
153 except pkg.PackageError as e:
154 raise PackageStoreError("Failed to extract package to package store") from e
155
156 self._package_dirs[pkg.descriptor_id] = package_dir
157
158 def delete_package(self, descriptor_id):
159 """ Delete a stored DescriptorPackage
160
161 Arguments:
162 descriptor_id - The DescriptorPackage.descriptor_id
163
164 Raises:
165 PackageNotFoundError - The package could not be found
166 PackageStoreError - The package could not be deleted
167 """
168
169 if descriptor_id not in self._package_dirs:
170 raise PackageNotFoundError("Package %s does not exists", descriptor_id)
171
172 package_dir = self._get_package_dir(descriptor_id)
173 try:
174 if os.path.exists(package_dir):
175 self._log.debug("Removing stored package directory: %s", package_dir)
176 shutil.rmtree(package_dir)
177 except OSError as e:
178 raise PackageStoreError(
179 "Failed to remove stored package directory: %s", package_dir
180 ) from e
181
182 del self._package_dirs[descriptor_id]
183
184 def update_package(self, pkg):
185 """ Update a stored DescriptorPackage
186
187 Arguments:
188 pkg - A DescriptorPackage
189
190 Raises:
191 PackageNotFoundError - The package could not be found
192 PackageStoreError - The package could not be deleted
193 """
194 self.delete_package(pkg.descriptor_id)
195 self.store_package(pkg)
196
197
198 class NsdPackageFilesystemStore(PackageFilesystemStore):
199 DEFAULT_ROOT_DIR = os.path.join(
200 os.environ["RIFT_ARTIFACTS"],
201 "launchpad", "packages", "nsd"
202 )
203
204 def __init__(self, log, root_dir=DEFAULT_ROOT_DIR):
205 super().__init__(log, root_dir)
206
207
208 class VnfdPackageFilesystemStore(PackageFilesystemStore):
209 DEFAULT_ROOT_DIR = os.path.join(
210 os.environ["RIFT_ARTIFACTS"],
211 "launchpad", "packages", "vnfd"
212 )
213
214 def __init__(self, log, root_dir=DEFAULT_ROOT_DIR):
215 super().__init__(log, root_dir)
216