4 # Copyright 2016 RIFT.IO Inc
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
31 gi
.require_version('RwYang', '1.0')
32 gi
.require_version('RwProjectVnfdYang', '1.0')
33 gi
.require_version('RwProjectNsdYang', '1.0')
34 gi
.require_version('NsdYang', '1.0')
35 gi
.require_version('VnfdYang', '1.0')
37 from gi
.repository
import (
39 RwProjectVnfdYang
as RwVnfdYang
,
40 RwProjectNsdYang
as RwNsdYang
,
45 import rift
.package
.store
46 import rift
.package
.cloud_init
48 logger
= logging
.getLogger("rift2openmano.py")
51 class VNFNotFoundError(Exception):
55 class RiftNSD(object):
56 model
= RwYang
.Model
.create_libyang()
57 model
.load_module('nsd')
59 def __init__(self
, descriptor
):
60 self
._nsd
= descriptor
75 return [c
.vnfd_id_ref
for c
in self
._nsd
.constituent_vnfd
]
78 def constituent_vnfds(self
):
79 return self
._nsd
.constituent_vnfd
82 def scaling_group_descriptor(self
):
83 return self
._nsd
.scaling_group_descriptor
91 return self
._nsd
.connection_point
94 def description(self
):
95 return self
._nsd
.description
98 def from_xml_file_hdl(cls
, hdl
):
100 descriptor
= NsdYang
.YangData_Nsd_NsdCatalog_Nsd()
101 descriptor
.from_xml_v2(RiftNSD
.model
, hdl
.read())
102 return cls(descriptor
)
105 def from_yaml_file_hdl(cls
, hdl
):
107 descriptor
= NsdYang
.YangData_Nsd_NsdCatalog_Nsd()
108 descriptor
.from_yaml(RiftNSD
.model
, hdl
.read())
109 return cls(descriptor
)
112 descriptor
= NsdYang
.YangData_Nsd_NsdCatalog_Nsd
.from_dict(self
._nsd
.as_dict(), ignore_missing_keys
=True).to_json_without_namespace(RiftNSD
.model
)
116 class RiftVNFD(object):
117 model
= RwYang
.Model
.create_libyang()
118 model
.load_module('vnfd')
120 def __init__(self
, descriptor
):
121 self
._vnfd
= descriptor
124 return str(self
._vnfd
)
132 return self
._vnfd
.name
135 def description(self
):
136 return self
._vnfd
.description
140 return self
._vnfd
.connection_point
144 return self
._vnfd
.vdu
147 def internal_vlds(self
):
148 return self
._vnfd
.internal_vld
151 def from_xml_file_hdl(cls
, hdl
):
153 descriptor
= VnfdYang
.YangData_Vnfd_VnfdCatalog_Vnfd()
154 descriptor
.from_xml_v2(RiftVNFD
.model
, hdl
.read())
155 return cls(descriptor
)
158 def from_yaml_file_hdl(cls
, hdl
):
160 descriptor
= VnfdYang
.YangData_Vnfd_VnfdCatalog_Vnfd()
161 descriptor
.from_yaml(RiftVNFD
.model
, hdl
.read())
162 return cls(descriptor
)
165 descriptor
= VnfdYang
.YangData_Vnfd_VnfdCatalog_Vnfd
.from_dict(self
._vnfd
.as_dict(), ignore_missing_keys
=True).to_json_without_namespace(RiftVNFD
.model
)
169 def is_writable_directory(dir_path
):
170 """ Returns True if dir_path is writable, False otherwise
173 dir_path - A directory path
175 if not os
.path
.exists(dir_path
):
176 raise ValueError("Directory does not exist: %s", dir_path
)
179 testfile
= tempfile
.TemporaryFile(dir=dir_path
)
187 def create_vnfd_from_files(vnfd_file_hdls
):
188 """ Create a list of RiftVNFD instances from xml/yaml file handles
191 vnfd_file_hdls - Rift VNFD XML/YAML file handles
194 A list of RiftVNFD instances
197 for vnfd_file_hdl
in vnfd_file_hdls
:
198 if vnfd_file_hdl
.name
.endswith("yaml") or vnfd_file_hdl
.name
.endswith("yaml"):
199 vnfd
= RiftVNFD
.from_yaml_file_hdl(vnfd_file_hdl
)
201 vnfd
= RiftVNFD
.from_xml_file_hdl(vnfd_file_hdl
)
202 vnfd_dict
[vnfd
.id] = vnfd
207 def create_nsd_from_file(nsd_file_hdl
):
208 """ Create a list of RiftNSD instances from yaml/xml file handles
211 nsd_file_hdls - Rift NSD XML/yaml file handles
214 A list of RiftNSD instances
216 if nsd_file_hdl
.name
.endswith("yaml") or nsd_file_hdl
.name
.endswith("yaml"):
217 nsd
= RiftNSD
.from_yaml_file_hdl(nsd_file_hdl
)
219 nsd
= RiftNSD
.from_xml_file_hdl(nsd_file_hdl
)
224 return collections
.defaultdict(dict)
226 def convert_vnfd_name(vnfd_name
, member_idx
):
227 return vnfd_name
+ "__" + str(member_idx
)
230 def rift2openmano_nsd(rift_nsd
, rift_vnfds
, openmano_vnfd_ids
, http_api
, rift_vnfd_id
=None):
232 if rift_vnfd_id
is None:
233 for vnfd_id
in rift_nsd
.vnfd_ids
:
234 if vnfd_id
not in rift_vnfds
:
235 raise VNFNotFoundError("VNF id %s not provided" % vnfd_id
)
237 openmano_nsd_im_body
= json
.loads(rift_nsd
.from_dict())
238 openmano_nsd_api_format
= {
240 "nsd": [openmano_nsd_im_body
['nsd-catalog']['nsd'][0]]
244 openmano_nsd
= http_api
.post_nsd_v3(openmano_nsd_api_format
)
248 except Exception as e
:
252 def rift2openmano_vnfd_nsd(rift_nsd
, rift_vnfds
, openmano_vnfd_ids
, http_api
, rift_vnfd_id
=None):
254 if rift_vnfd_id
not in rift_vnfds
:
255 raise VNFNotFoundError("VNF id %s not provided" % rift_vnfd_id
)
257 # This is the scaling NSD Descriptor. Can use the NSD IM Model.
258 openmano_nsd_im_body
= json
.loads(rift_nsd
.from_dict())
260 openmano_nsd_api_format
= {
262 "nsd": [openmano_nsd_im_body
['nsd-catalog']['nsd'][0]]
266 openmano_nsd
= http_api
.post_nsd_v3(openmano_nsd_api_format
)
270 except Exception as e
:
275 def cloud_init(rift_vnfd_id
, vdu
, project_name
='default'):
276 """ Populate cloud-init with script from
277 either the inline contents or from the file provided
279 vnfd_package_store
= rift
.package
.store
.VnfdPackageFilesystemStore(logger
, project
=project_name
)
281 cloud_init_msg
= None
282 if 'cloud-init' in vdu
:
283 logger
.debug("cloud-init script provided inline %s", vdu
['cloud-init'])
284 cloud_init_msg
= vdu
['cloud-init']
285 elif 'cloud-init-file' in vdu
:
286 # Get cloud-init script contents from the file provided in the cloud_init_file param
287 logger
.debug("cloud-init script provided in file %s", vdu
['cloud-init-file'])
288 filename
= vdu
['cloud-init-file']
289 vnfd_package_store
.refresh()
290 stored_package
= vnfd_package_store
.get_package(rift_vnfd_id
)
291 cloud_init_extractor
= rift
.package
.cloud_init
.PackageCloudInitExtractor(logger
)
293 cloud_init_msg
= cloud_init_extractor
.read_script(stored_package
, filename
)
294 except rift
.package
.cloud_init
.CloudInitExtractionError
as e
:
297 logger
.debug("VDU translation: cloud-init script not provided")
300 logger
.debug("Current cloud init msg is {}".format(cloud_init_msg
))
301 return cloud_init_msg
303 def config_file_init(rift_vnfd_id
, vdu
, cfg_file
, project_name
='default'):
304 """ Populate config file init with file provided
306 vnfd_package_store
= rift
.package
.store
.VnfdPackageFilesystemStore(logger
, project
=project_name
)
308 # Get script contents from the file provided in the cloud_init directory
309 logger
.debug("config file script provided in file {}".format(cfg_file
))
311 vnfd_package_store
.refresh()
312 stored_package
= vnfd_package_store
.get_package(rift_vnfd_id
)
313 cloud_init_extractor
= rift
.package
.cloud_init
.PackageCloudInitExtractor(logger
)
315 cfg_file_msg
= cloud_init_extractor
.read_script(stored_package
, filename
)
316 except rift
.package
.cloud_init
.CloudInitExtractionError
as e
:
319 logger
.debug("Current config file msg is {}".format(cfg_file_msg
))
322 def rift2openmano_vnfd(rift_vnfd
, rift_nsd
, http_api
, project
):
324 openmano_vnfd_im_body
= json
.loads(rift_vnfd
.from_dict())
326 # All type_yang leafs renamed to type
328 vnfd_dict
= openmano_vnfd_im_body
['vnfd-catalog']['vnfd'][0]
330 if 'vdu' in vnfd_dict
:
331 for vdu
in vnfd_dict
['vdu']:
332 if 'cloud-init-file' in vdu
:
333 # Replacing the leaf with the actual contents of the file.
334 # The RO does not have the ability to read files yet.
335 vdu
['cloud-init-file'] = cloud_init(vnfd_dict
['id'], vdu
, project
)
336 elif 'cloud-init' in vdu
:
337 vdu
['cloud-init'] = cloud_init(vnfd_dict
['id'], vdu
, project
)
339 if 'supplemental-boot-data' in vdu
:
340 if 'config-file' in vdu
['supplemental-boot-data']:
341 for config_file
in vdu
['supplemental-boot-data']['config-file']:
342 # Replacing the leaf with the actual contents of the file.
343 # The RO does not have the ability to read files yet.
344 config_file
['source'] = config_file_init(vnfd_dict
['id'], vdu
, config_file
['source'], project
)
346 openmano_vnfd_api_format
= {
347 "vnfd:vnfd-catalog": {
351 openmano_vnfd
= http_api
.post_vnfd_v3(openmano_vnfd_api_format
)
355 except Exception as e
:
361 def parse_args(argv
=sys
.argv
[1:]):
362 """ Parse the command line arguments
365 arv - The list of arguments to parse
368 Argparse Namespace instance
370 parser
= argparse
.ArgumentParser()
374 help="Directory to output converted descriptors. Default is stdout",
378 '-n', '--nsd-file-hdl',
380 type=argparse
.FileType('r'),
381 help="Rift NSD Descriptor File",
385 '-v', '--vnfd-file-hdls',
388 type=argparse
.FileType('r'),
389 help="Rift VNFD Descriptor File",
392 args
= parser
.parse_args(argv
)
394 if not os
.path
.exists(args
.outdir
):
395 os
.makedirs(args
.outdir
)
397 if not is_writable_directory(args
.outdir
):
398 logging
.error("Directory %s is not writable", args
.outdir
)
404 def write_yaml_to_file(name
, outdir
, desc_dict
):
405 file_name
= "%s.yaml" % name
406 yaml_str
= yaml
.dump(desc_dict
)
408 sys
.stdout
.write(yaml_str
)
411 file_path
= os
.path
.join(outdir
, file_name
)
412 dir_path
= os
.path
.dirname(file_path
)
413 if not os
.path
.exists(dir_path
):
414 os
.makedirs(dir_path
)
416 with
open(file_path
, "w") as hdl
:
419 logger
.info("Wrote descriptor to %s", file_path
)
422 def main(argv
=sys
.argv
[1:]):
423 args
= parse_args(argv
)
425 openmano_vnfr_ids
= dict()
427 if args
.vnfd_file_hdls
is not None:
428 vnf_dict
= create_vnfd_from_files(args
.vnfd_file_hdls
)
430 for vnfd
in vnf_dict
:
431 openmano_vnfr_ids
[vnfd
] = vnfd
433 if args
.nsd_file_hdl
is not None:
434 nsd
= create_nsd_from_file(args
.nsd_file_hdl
)
436 openmano_nsd
= rift2openmano_nsd(nsd
, vnf_dict
, openmano_vnfr_ids
)
437 vnfd_nsd
= rift2openmano_vnfd_nsd(nsd
, vnf_dict
, openmano_vnfr_ids
)
438 write_yaml_to_file(openmano_nsd
["name"], args
.outdir
, openmano_nsd
)
439 write_yaml_to_file(vnfd_nsd
["name"], args
.outdir
, vnfd_nsd
)
441 for vnf
in vnf_dict
.values():
442 openmano_vnf
= rift2openmano_vnfd(vnf
, nsd
)
443 write_yaml_to_file(openmano_vnf
["vnf"]["name"], args
.outdir
, openmano_vnf
)
446 if __name__
== "__main__":
447 logging
.basicConfig(level
=logging
.WARNING
)