[Bug 270] Copy icons to UI filesystem location when descriptor is copied. Also delete...
[osm/SO.git] / rwlaunchpad / plugins / rwpkgmgr / rift / tasklets / rwpkgmgr / downloader / copy.py
1 #
2 # Copyright 2017 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): Nandan Sinha
17 #
18
19 import os
20 import uuid
21 import shutil
22 import enum
23
24 import gi
25 gi.require_version('RwVnfdYang', '1.0')
26 gi.require_version('RwNsdYang', '1.0')
27 from gi.repository import (
28 RwYang,
29 NsdYang,
30 VnfdYang,
31 RwVnfdYang,
32 RwNsdYang,
33 RwPkgMgmtYang
34 )
35
36 import rift.package.icon as icon
37
38 class PackageCopyError(Exception):
39 pass
40
41 class CopyStatus(enum.Enum):
42 UNINITIATED = 0
43 STARTED = 1
44 IN_PROGRESS = 2
45 COMPLETED = 3
46 FAILED = 4
47 CANCELLED = 5
48
49 TaskStatus = RwPkgMgmtYang.TaskStatus
50
51 class CopyMeta:
52 STATUS_MAP = {
53 CopyStatus.STARTED: TaskStatus.QUEUED.value_nick.upper(),
54 CopyStatus.UNINITIATED: TaskStatus.QUEUED.value_nick.upper(),
55 CopyStatus.IN_PROGRESS: TaskStatus.IN_PROGRESS.value_nick.upper(),
56 CopyStatus.COMPLETED: TaskStatus.COMPLETED.value_nick.upper(),
57 CopyStatus.FAILED: TaskStatus.FAILED.value_nick.upper(),
58 CopyStatus.CANCELLED: TaskStatus.CANCELLED.value_nick.upper()
59 }
60
61 def __init__(self, transaction_id):
62 self.transaction_id = transaction_id
63 self.state = CopyStatus.UNINITIATED
64
65 def set_state(self, state):
66 self.state = state
67
68 def as_dict(self):
69 return self.__dict__
70
71 def to_yang(self):
72 job = RwPkgMgmtYang.CopyJob.from_dict({
73 "transaction_id": self.transaction_id,
74 "status": CopyMeta.STATUS_MAP[self.state]
75 })
76 return job
77
78 class PackageFileCopier:
79 DESCRIPTOR_MAP = {
80 "vnfd": (RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd, 'vnfd rw-vnfd'),
81 "nsd" : (RwNsdYang.YangData_Nsd_NsdCatalog_Nsd, 'nsd rw-nsd')
82 }
83
84 @classmethod
85 def from_rpc_input(cls, rpc_input, proxy, log=None):
86 return cls(
87 rpc_input.package_id,
88 rpc_input.package_type,
89 rpc_input.package_name,
90 proxy = proxy,
91 log=log)
92
93 def __init__(self,
94 pkg_id,
95 pkg_type,
96 pkg_name,
97 proxy,
98 log):
99 self.src_package_id = pkg_id
100 self.package_type = pkg_type.lower()
101 self.dest_package_name = pkg_name
102 self.dest_package_id = str(uuid.uuid4())
103 self.transaction_id = str(uuid.uuid4())
104 self.proxy = proxy
105 self.log = log
106 self.meta = CopyMeta(self.transaction_id)
107 self.src_package = None
108 self.dest_desc_msg = None
109
110 # Start of delegate calls
111 def call_delegate(self, event):
112 if not self.delegate:
113 return
114
115 # Send out the descriptor message to be posted on success
116 # Otherwise send out the CopyJob yang conversion from meta object.
117 if event == "on_download_succeeded":
118 getattr(self.delegate, event)(self.dest_desc_msg)
119 else:
120 getattr(self.delegate, event)(self.meta.to_yang())
121
122 def _copy_tree(self):
123 """
124 Locate directory tree of the source descriptor folder.
125 Copy directory tree to destination descriptor folder.
126
127 """
128 self.copy_progress()
129
130 store = self.proxy._get_store(self.package_type)
131 src_path = store._get_package_dir(self.src_package_id)
132 self.src_package = store.get_package(self.src_package_id)
133
134 self.dest_copy_path = os.path.join(
135 store.DEFAULT_ROOT_DIR,
136 self.dest_package_id)
137 self.log.debug("Copying contents from {src} to {dest}".
138 format(src=src_path, dest=self.dest_copy_path))
139
140 shutil.copytree(src_path, self.dest_copy_path)
141 # If there are icon files, also need to copy them in UI location
142 if os.path.exists(os.path.join(src_path, "icons")):
143 src_icon_path = os.path.join(
144 icon.PackageIconExtractor.DEFAULT_INSTALL_DIR,
145 self.package_type,
146 self.src_package_id)
147 dest_icon_path = os.path.join(
148 os.path.dirname(src_icon_path),
149 self.dest_package_id)
150
151 self.log.debug("Copying UI icon location from {} to {}".format(src_icon_path,
152 dest_icon_path))
153 shutil.copytree(src_icon_path, dest_icon_path)
154
155 def _create_descriptor_file(self):
156 """ Update descriptor file for the newly copied descriptor catalog.
157 Use the existing descriptor file to create a descriptor proto gi object,
158 change some identifiers, and create a new descriptor yaml file from it.
159
160 """
161 src_desc_file = self.src_package.descriptor_file
162 src_desc_contents = self.src_package.descriptor_msg.as_dict()
163 src_desc_contents.update(
164 id =self.dest_package_id,
165 name = self.dest_package_name,
166 short_name = self.dest_package_name
167 )
168
169 desc_cls, modules = PackageFileCopier.DESCRIPTOR_MAP[self.package_type]
170 self.dest_desc_msg = desc_cls.from_dict(src_desc_contents)
171 dest_desc_path = os.path.join(self.dest_copy_path,
172 "{pkg_name}_{pkg_type}.yaml".format(pkg_name=self.dest_package_name, pkg_type=self.package_type))
173 model = RwYang.Model.create_libncx()
174 for module in modules.split():
175 model.load_module(module)
176
177 with open(dest_desc_path, "w") as fh:
178 fh.write(self.dest_desc_msg.to_yaml(model))
179
180 copied_desc_file = os.path.join(self.dest_copy_path, os.path.basename(src_desc_file))
181 if os.path.exists(copied_desc_file):
182 self.log.debug("Deleting copied yaml from old source %s" % (copied_desc_file))
183 os.remove(copied_desc_file)
184
185 def copy(self):
186 try:
187 if self.package_type not in PackageFileCopier.DESCRIPTOR_MAP:
188 raise PackageCopyError("Package type {} not currently supported for copy operations".format(self.package_type))
189
190 self._copy_tree()
191 self._create_descriptor_file()
192 self.copy_succeeded()
193
194 except Exception as e:
195 self.log.exception(str(e))
196 self.copy_failed()
197
198 self.copy_finished()
199
200 def copy_failed(self):
201 self.meta.set_state(CopyStatus.FAILED)
202 self.call_delegate("on_download_failed")
203
204 def copy_progress(self):
205 self.meta.set_state(CopyStatus.IN_PROGRESS)
206 self.call_delegate("on_download_progress")
207
208 def copy_succeeded(self):
209 self.meta.set_state(CopyStatus.COMPLETED)
210 self.call_delegate("on_download_succeeded")
211
212 def copy_finished(self):
213 self.call_delegate("on_download_finished")
214