update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / rwlaunchpad / plugins / rwpkgmgr / rift / tasklets / rwpkgmgr / proxy / filesystem.py
1 #
2 # Copyright 2016 RIFT.IO Inc
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16 # Author(s): Varun Prasad
17 # Creation Date: 09/25/2016
18 #
19
20 import asyncio
21 import os
22
23 import rift.package.store as store
24 import rift.package.package
25 import rift.package.icon as icon
26 import rift.package.checksums as checksums
27
28 from .base import AbstractPackageManagerProxy
29 from rift.tasklets.rwlaunchpad import image
30
31 class UnknownPackageType(Exception):
32 pass
33
34
35 class FileSystemProxy(AbstractPackageManagerProxy):
36 """Proxy for Filesystem based store.
37 """
38 PACKAGE_TYPE_MAP = {"vnfd": store.VnfdPackageFilesystemStore,
39 "nsd": store.NsdPackageFilesystemStore}
40
41 # Refer: https://confluence.riftio.com/display/ATG/Launchpad+package+formats
42 SCHEMA = {
43 "nsd": ["icons", "ns_config", "scripts", "vnf_config"],
44 "vnfd": ["charms", "cloud_init", "icons", "images", "scripts", "readme", "test", "doc"]
45 }
46
47 SCHEMA_TO_PERMS = {'scripts': 0o777}
48
49 def __init__(self, loop, log, dts):
50 self.loop = loop
51 self.log = log
52 self.dts = dts
53 self.store_cache = {}
54 self.uploader = image.ImageUploader(self.log, self.loop, self.dts)
55
56 def _get_store(self, package_type, project_name = None):
57 store_cls = self.PACKAGE_TYPE_MAP[package_type]
58 self.store_cache[package_type] = store_cls(self.log, project=project_name)
59 store = self.store_cache[package_type]
60
61 return store
62
63 @asyncio.coroutine
64 def endpoint(self, package_type, package_id, project_name=None):
65 package_type = package_type.lower()
66 if package_type not in self.PACKAGE_TYPE_MAP:
67 raise UnknownPackageType()
68
69 store = self._get_store(package_type, project_name)
70
71 package = store._get_package_dir(package_id)
72 rel_path = os.path.relpath(package, start=os.path.dirname(store.root_dir))
73
74 url = "https://127.0.0.1:8008/mano/api/package/{}/{}".format(package_type, rel_path)
75
76 return url
77
78 @asyncio.coroutine
79 def schema(self, package_type):
80 package_type = package_type.lower()
81 if package_type not in self.PACKAGE_TYPE_MAP:
82 raise UnknownPackageType()
83
84 return self.SCHEMA[package_type]
85
86 def package_file_add(self, new_file, package_type, package_id, package_path, package_file_type, project_name):
87 # Get the schema from thr package path
88 # the first part will always be the vnfd/nsd name
89 mode = 0o664
90
91 # for files other than README, create the package path from the asset type, e.g. icons/icon1.png
92 # for README files, strip off any leading '/'
93 file_name = package_path
94 package_path = package_file_type + "/" + package_path \
95 if package_file_type != "readme" else package_path.strip('/')
96
97 components = package_path.split("/")
98 if len(components) > 2:
99 schema = components[1]
100 mode = self.SCHEMA_TO_PERMS.get(schema, mode)
101
102 # Fetch the package object
103 package_type = package_type.lower()
104 store = self._get_store(package_type, project_name)
105 package = store.get_package(package_id)
106
107 # Construct abs path of the destination obj
108 path = store._get_package_dir(package_id)
109 dest_file = os.path.join(path, package.prefix, package_path)
110
111 # Insert (by copy) the file in the package location. For icons,
112 # insert also in UI location for UI to pickup
113 try:
114 self.log.debug("Inserting file {} in the destination {} - {} ".format(dest_file, package_path, dest_file))
115 package.insert_file(new_file, dest_file, package_path, mode=mode)
116
117 if package_file_type == 'icons':
118 icon_extract = icon.PackageIconExtractor(self.log)
119 icon_extract.extract_icons(package)
120
121 if package_file_type == 'images':
122 image_hdl = package.open(package_path)
123 image_checksum = checksums.checksum(image_hdl)
124
125 try:
126 self.uploader.upload_image(file_name, image_checksum, image_hdl, {})
127 self.uploader.upload_image_to_cloud_accounts(file_name, image_checksum, project_name)
128 finally:
129 _ = image_hdl.close()
130 except rift.package.package.PackageAppendError as e:
131 self.log.exception(e)
132 return False
133
134 self.log.debug("File insertion complete at {}".format(dest_file))
135 return True
136
137 def package_file_delete(self, package_type, package_id, package_path, package_file_type, project_name):
138 package_type = package_type.lower()
139 store = self._get_store(package_type, project_name)
140 package = store.get_package(package_id)
141
142 # for files other than README, create the relative package path from the asset type
143 package_path_rel = package_file_type + "/" + package_path \
144 if package_file_type != "readme" else package_path
145
146 # package_path has to be relative, so strip off the starting slash if
147 # provided incorrectly.
148 if package_path_rel[0] == "/":
149 package_path_rel = package_path_rel[1:]
150
151 # Construct abs path of the destination obj
152 path = store._get_package_dir(package_id)
153 dest_file = os.path.join(path, package.prefix, package_path_rel)
154
155 try:
156 package.delete_file(dest_file, package_path_rel)
157
158 if package_file_type == 'icons':
159 ui_icon_path = os.path.join(
160 icon.PackageIconExtractor.DEFAULT_INSTALL_DIR,
161 package_type,
162 package_id)
163 if os.path.exists(ui_icon_path):
164 icon_file = os.path.join(ui_icon_path, package_path)
165 self.log.debug("Deleting UI icon file path {}".format(icon_file))
166 os.remove(icon_file)
167
168 except rift.package.package.PackageAppendError as e:
169 self.log.exception(e)
170 return False
171
172 return True
173