Commit to master [RIFT 15737] Remove logic for deletion of folder on deletion of...
[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 self.refresh()
114
115 if package_id not in self._package_dirs:
116 msg = "Package %s not found in %s" % (package_id, self._root_dir)
117 raise PackageNotFoundError(msg)
118
119 package_files = self._get_package_files(package_id)
120 package_dir = self._get_package_dir(package_id)
121
122 def do_open(pkg_file):
123 pkg_path = os.path.join(package_dir, pkg_file)
124 return open(pkg_path, "rb")
125
126 pkg = package.DescriptorPackage.from_package_files(self._log, do_open, package_files)
127 for pkg_file in package_files:
128 pkg.add_file(pkg_file)
129
130 return pkg
131
132 def store_package(self, pkg):
133 """ Store a DescriptorPackage to disk
134
135 Arguments:
136 pkg - A DescriptorPackage
137
138 Raises:
139 PackageStoreError - The package could not be stored
140 """
141 if pkg.descriptor_id in self._package_dirs:
142 raise PackageExistsError("Package %s already exists", pkg.descriptor_id)
143
144 package_dir = self._get_package_dir(pkg.descriptor_id)
145
146 try:
147 os.makedirs(package_dir, exist_ok=True)
148 except OSError as e:
149 raise PackageStoreError("Failed to create package dir: %s", package_dir) from e
150
151 try:
152 self._log.debug("Storing package in dir %s", package_dir)
153 pkg.extract(package_dir)
154 self._log.debug("Package stored in dir %s", package_dir)
155 except pkg.PackageError as e:
156 raise PackageStoreError("Failed to extract package to package store") from e
157
158 self._package_dirs[pkg.descriptor_id] = package_dir
159
160 def delete_package(self, descriptor_id):
161 """ Delete a stored DescriptorPackage
162
163 Arguments:
164 descriptor_id - The DescriptorPackage.descriptor_id
165
166 Raises:
167 PackageNotFoundError - The package could not be found
168 PackageStoreError - The package could not be deleted
169 """
170
171 if descriptor_id not in self._package_dirs:
172 raise PackageNotFoundError("Package %s does not exists", descriptor_id)
173
174 package_dir = self._get_package_dir(descriptor_id)
175 try:
176 if os.path.exists(package_dir):
177 self._log.debug("Removing stored package directory: %s", package_dir)
178 shutil.rmtree(package_dir)
179 except OSError as e:
180 raise PackageStoreError(
181 "Failed to remove stored package directory: %s", package_dir
182 ) from e
183
184 del self._package_dirs[descriptor_id]
185
186 def update_package(self, pkg):
187 """ Update a stored DescriptorPackage
188
189 Arguments:
190 pkg - A DescriptorPackage
191
192 Raises:
193 PackageNotFoundError - The package could not be found
194 PackageStoreError - The package could not be deleted
195 """
196 self.delete_package(pkg.descriptor_id)
197 self.store_package(pkg)
198
199
200 class NsdPackageFilesystemStore(PackageFilesystemStore):
201 DEFAULT_ROOT_DIR = os.path.join(
202 os.environ["RIFT_ARTIFACTS"],
203 "launchpad", "packages", "nsd"
204 )
205
206 def __init__(self, log, root_dir=DEFAULT_ROOT_DIR):
207 super().__init__(log, root_dir)
208
209
210 class VnfdPackageFilesystemStore(PackageFilesystemStore):
211 DEFAULT_ROOT_DIR = os.path.join(
212 os.environ["RIFT_ARTIFACTS"],
213 "launchpad", "packages", "vnfd"
214 )
215
216 def __init__(self, log, root_dir=DEFAULT_ROOT_DIR):
217 super().__init__(log, root_dir)
218