Revert "Full Juju Charm support"
[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 def _get_package_dir(self, package_id):
57 self._log.debug("Package dir {}, {}".format(self._root_dir, 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, project=None):
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 try:
146 os.makedirs(package_dir, exist_ok=True)
147 except OSError as e:
148 raise PackageStoreError("Failed to create package dir: %s", package_dir) from e
149
150 try:
151 self._log.debug("Storing package in dir %s", package_dir)
152 pkg.extract(package_dir)
153 self._log.debug("Package stored in dir %s", package_dir)
154 except pkg.PackageError as e:
155 raise PackageStoreError("Failed to extract package to package store") from e
156
157 self._package_dirs[pkg.descriptor_id] = package_dir
158
159 def delete_package(self, descriptor_id):
160 """ Delete a stored DescriptorPackage
161
162 Arguments:
163 descriptor_id - The DescriptorPackage.descriptor_id
164
165 Raises:
166 PackageNotFoundError - The package could not be found
167 PackageStoreError - The package could not be deleted
168 """
169
170 self.refresh()
171
172 if descriptor_id not in self._package_dirs:
173 raise PackageNotFoundError("Package %s does not exists", descriptor_id)
174
175 package_dir = self._get_package_dir(descriptor_id)
176 try:
177 if os.path.exists(package_dir):
178 self._log.debug("Removing stored package directory: %s", package_dir)
179 shutil.rmtree(package_dir)
180 except OSError as e:
181 raise PackageStoreError(
182 "Failed to remove stored package directory: %s", package_dir
183 ) from e
184
185 del self._package_dirs[descriptor_id]
186
187 def update_package(self, pkg):
188 """ Update a stored DescriptorPackage
189
190 Arguments:
191 pkg - A DescriptorPackage
192
193 Raises:
194 PackageNotFoundError - The package could not be found
195 PackageStoreError - The package could not be deleted
196 """
197 self.delete_package(pkg.descriptor_id)
198 self.store_package(pkg)
199
200
201 class NsdPackageFilesystemStore(PackageFilesystemStore):
202 DEFAULT_ROOT_DIR = os.path.join(
203 os.environ["RIFT_VAR_ROOT"],
204 "launchpad", "packages", "nsd"
205 )
206
207 def __init__(self, log, root_dir=DEFAULT_ROOT_DIR, project=None):
208 root_dir = root_dir if not project else os.path.join(root_dir, project)
209 super().__init__(log, root_dir)
210
211
212 class VnfdPackageFilesystemStore(PackageFilesystemStore):
213 DEFAULT_ROOT_DIR = os.path.join(
214 os.environ["RIFT_VAR_ROOT"],
215 "launchpad", "packages", "vnfd"
216 )
217
218 def __init__(self, log, root_dir=DEFAULT_ROOT_DIR, project=None):
219 root_dir = root_dir if not project else os.path.join(root_dir, project)
220 super().__init__(log, root_dir)