2 # Copyright 2017 RIFT.IO Inc
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 # Author(s): Nandan Sinha
25 gi
.require_version('RwVnfdYang', '1.0')
26 gi
.require_version('RwNsdYang', '1.0')
27 from gi
.repository
import (
36 import rift
.package
.icon
as icon
38 class PackageCopyError(Exception):
41 class CopyStatus(enum
.Enum
):
49 TaskStatus
= RwPkgMgmtYang
.TaskStatus
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()
61 def __init__(self
, transaction_id
):
62 self
.transaction_id
= transaction_id
63 self
.state
= CopyStatus
.UNINITIATED
65 def set_state(self
, state
):
72 job
= RwPkgMgmtYang
.CopyJob
.from_dict({
73 "transaction_id": self
.transaction_id
,
74 "status": CopyMeta
.STATUS_MAP
[self
.state
]
78 class PackageFileCopier
:
80 "vnfd": (RwVnfdYang
.YangData_Vnfd_VnfdCatalog_Vnfd
, 'vnfd rw-vnfd'),
81 "nsd" : (RwNsdYang
.YangData_Nsd_NsdCatalog_Nsd
, 'nsd rw-nsd')
85 def from_rpc_input(cls
, rpc_input
, proxy
, log
=None):
88 rpc_input
.package_type
,
89 rpc_input
.package_name
,
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())
106 self
.meta
= CopyMeta(self
.transaction_id
)
107 self
.src_package
= None
108 self
.dest_desc_msg
= None
110 # Start of delegate calls
111 def call_delegate(self
, event
):
112 if not self
.delegate
:
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
)
120 getattr(self
.delegate
, event
)(self
.meta
.to_yang())
122 def _copy_tree(self
):
124 Locate directory tree of the source descriptor folder.
125 Copy directory tree to destination descriptor folder.
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
)
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
))
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
,
147 dest_icon_path
= os
.path
.join(
148 os
.path
.dirname(src_icon_path
),
149 self
.dest_package_id
)
151 self
.log
.debug("Copying UI icon location from {} to {}".format(src_icon_path
,
153 shutil
.copytree(src_icon_path
, dest_icon_path
)
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.
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
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
)
177 with
open(dest_desc_path
, "w") as fh
:
178 fh
.write(self
.dest_desc_msg
.to_yaml(model
))
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
)
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
))
191 self
._create
_descriptor
_file
()
192 self
.copy_succeeded()
194 except Exception as e
:
195 self
.log
.exception(str(e
))
200 def copy_failed(self
):
201 self
.meta
.set_state(CopyStatus
.FAILED
)
202 self
.call_delegate("on_download_failed")
204 def copy_progress(self
):
205 self
.meta
.set_state(CopyStatus
.IN_PROGRESS
)
206 self
.call_delegate("on_download_progress")
208 def copy_succeeded(self
):
209 self
.meta
.set_state(CopyStatus
.COMPLETED
)
210 self
.call_delegate("on_download_succeeded")
212 def copy_finished(self
):
213 self
.call_delegate("on_download_finished")