fa3dd3e351326a5d76e399dcce1a2900e1901262
[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 store = self.proxy._get_store(self.package_type)
127 src_path = store._get_package_dir(self.src_package_id)
128 self.src_package = store.get_package(self.src_package_id)
129 src_desc_name = self.src_package.descriptor_name
130 src_copy_path = os.path.join(src_path, src_desc_name)
131
132 self.dest_copy_path = os.path.join(store.DEFAULT_ROOT_DIR,
133 self.dest_package_id,
134 self.dest_package_name)
135 self.log.debug("Copying contents from {src} to {dest}".
136 format(src=src_copy_path, dest=self.dest_copy_path))
137
138 shutil.copytree(src_copy_path, self.dest_copy_path)
139
140 def _create_descriptor_file(self):
141 """ Update descriptor file for the newly copied descriptor catalog.
142 Use the existing descriptor file to create a descriptor proto gi object,
143 change some identifiers, and create a new descriptor yaml file from it.
144
145 """
146 src_desc_file = self.src_package.descriptor_file
147 src_desc_contents = self.src_package.descriptor_msg.as_dict()
148 src_desc_contents.update(
149 id =self.dest_package_id,
150 name = self.dest_package_name,
151 short_name = self.dest_package_name
152 )
153
154 desc_cls, modules = PackageFileCopier.DESCRIPTOR_MAP[self.package_type]
155 self.dest_desc_msg = desc_cls.from_dict(src_desc_contents)
156 dest_desc_path = os.path.join(self.dest_copy_path,
157 "{pkg_name}_{pkg_type}.yaml".format(pkg_name=self.dest_package_name, pkg_type=self.package_type))
158 model = RwYang.Model.create_libncx()
159 for module in modules.split():
160 model.load_module(module)
161
162 with open(dest_desc_path, "w") as fh:
163 fh.write(self.dest_desc_msg.to_yaml(model))
164
165 copied_desc_file = os.path.join(self.dest_copy_path, os.path.basename(src_desc_file))
166 if os.path.exists(copied_desc_file):
167 self.log.debug("Deleting copied yaml from old source %s" % (copied_desc_file))
168 os.remove(copied_desc_file)
169
170 def copy(self):
171 try:
172 if self.package_type not in PackageFileCopier.DESCRIPTOR_MAP:
173 raise PackageCopyError("Package type {} not currently supported for copy operations".format(self.package_type))
174
175 self._copy_tree()
176 self._create_descriptor_file()
177 self.copy_succeeded()
178
179 except Exception as e:
180 self.log.exception(str(e))
181 self.copy_failed()
182
183 self.copy_finished()
184
185 def copy_failed(self):
186 self.meta.set_state(CopyStatus.FAILED)
187 self.call_delegate("on_download_failed")
188
189 def copy_progress(self):
190 self.meta.set_state(CopyStatus.IN_PROGRESS)
191 self.call_delegate("on_download_progress")
192
193 def copy_succeeded(self):
194 self.meta.set_state(CopyStatus.COMPLETED)
195 self.call_delegate("on_download_succeeded")
196
197 def copy_finished(self):
198 self.call_delegate("on_download_finished")
199