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