6 # Licensed under the Apache License, Version 2.0 (the "License"); you may
7 # not use this file except in compliance with the License. You may obtain
8 # 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, WITHOUT
14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 # License for the specific language governing permissions and limitations
25 from jinja2
import Environment
, PackageLoader
26 from osm_im
.validation
import Validation
as validation_im
27 from osm_im
.validation
import ValidationException
28 from osm_im
import im_translation
29 from osmclient
.common
import package_handling
as package_handling
30 from osmclient
.common
.exceptions
import ClientException
31 from osmclient
.common
import utils
32 from .sol004_package
import SOL004Package
33 from .sol007_package
import SOL007Package
37 class PackageTool(object):
38 def __init__(self
, client
=None):
40 self
._logger
= logging
.getLogger("osmclient")
41 self
._validator
= validation_im()
62 **Create a package descriptor**
65 - package_type: [vnf, ns, nst]
66 - base directory: path of destination folder
67 - package_name: is the name of the package to be created
68 - image: specify the image of the vdu
69 - vcpu: number of virtual cpus of the vdu
70 - memory: amount of memory in MB pf the vdu
71 - storage: amount of storage in GB of the vdu
72 - interfaces: number of interfaces besides management interface
73 - vendor: vendor name of the vnf/ns
74 - detailed: include all possible values for NSD, VNFD, NST
75 - netslice_subnets: number of netslice_subnets for the NST
76 - netslice_vlds: number of virtual link descriptors for the NST
77 - old: flag to create a descriptor using the previous OSM format (pre SOL006, OSM<9)
81 self
._logger
.debug("")
82 # print("location: {}".format(osmclient.__path__))
83 file_loader
= PackageLoader("osmclient")
84 env
= Environment(loader
=file_loader
, autoescape
=True)
85 if package_type
== "ns":
86 template
= env
.get_template("nsd.yaml.j2" if not old
else "nsd_old.yaml.j2")
92 "interfaces": interfaces
,
95 elif package_type
== "vnf":
96 template
= env
.get_template(
97 "vnfd.yaml.j2" if not old
else "vnfd_old.yaml.j2"
100 "name": package_name
,
104 "interfaces": interfaces
,
109 "detailed": detailed
,
111 elif package_type
== "nst":
112 # TODO: repo-index did not support nst in OSM<9, no changes in template
113 template
= env
.get_template("nst.yaml.j2")
115 "name": package_name
,
117 "interfaces": interfaces
,
118 "netslice_subnets": netslice_subnets
,
119 "netslice_vlds": netslice_vlds
,
120 "detailed": detailed
,
123 raise ClientException(
124 "Wrong descriptor type {}. Options: ns, vnf, nst".format(package_type
)
127 self
._logger
.debug("To be rendered: {}".format(content
))
128 output
= template
.render(content
)
129 self
._logger
.debug(output
)
131 structure
= self
.discover_folder_structure(
132 base_directory
, package_name
, override
134 if structure
.get("folders"):
135 self
.create_folders(structure
["folders"], package_type
)
136 if structure
.get("files"):
137 self
.create_files(structure
["files"], output
, package_type
)
140 def validate(self
, base_directory
, recursive
=True, old_format
=False):
142 **Validate OSM Descriptors given a path**
145 - base_directory is the root path for all descriptors
147 :return: List of dict of validated descriptors. keys: type, path, valid, error
149 self
._logger
.debug("")
152 descriptors_paths
= [
153 f
for f
in glob
.glob(base_directory
+ "/**/*.yaml", recursive
=recursive
)
156 descriptors_paths
= [
157 f
for f
in glob
.glob(base_directory
+ "/*.yaml", recursive
=recursive
)
159 self
._logger
.info("Base directory: {}".format(base_directory
))
161 "{} Descriptors found to validate".format(len(descriptors_paths
))
163 for desc_path
in descriptors_paths
:
164 with
open(desc_path
) as descriptor_file
:
165 descriptor_data
= descriptor_file
.read()
168 # TODO: refactor validation_im.yaml_validation to @staticmethod
169 desc_type
, descriptor_data
= validation_im
.yaml_validation(
170 self
, descriptor_data
172 self
._logger
.debug(f
"Validate {desc_type} {descriptor_data}")
174 if desc_type
== "vnfd" or desc_type
== "nsd":
176 "OSM descriptor '{}' written in an unsupported format. Please update to ETSI SOL006 format".format(
180 self
._logger
.warning(
181 "Package validation skipped. It can still be done with 'osm package-validate --old'"
183 self
._logger
.warning(
184 "Package build can still be done with 'osm package-build --skip-validation'"
186 raise Exception("Not SOL006 format")
187 validation_im
.pyangbind_validation(self
, desc_type
, descriptor_data
)
189 {"type": desc_type
, "path": desc_path
, "valid": "OK", "error": "-"}
191 except Exception as e
:
192 self
._logger
.error(f
"Validation error: {e}", exc_info
=True)
201 self
._logger
.debug(table
[-1])
204 def translate(self
, base_directory
, recursive
=True, dryrun
=False):
206 **Translate OSM Packages given a path**
209 - base_directory is the root path for all packages
211 :return: List of dict of translated packages. keys: current type, new type, path, valid, translated, error
213 self
._logger
.debug("")
216 descriptors_paths
= [
217 f
for f
in glob
.glob(base_directory
+ "/**/*.yaml", recursive
=recursive
)
220 descriptors_paths
= [
221 f
for f
in glob
.glob(base_directory
+ "/*.yaml", recursive
=recursive
)
223 print("Base directory: {}".format(base_directory
))
224 print("{} Descriptors found to validate".format(len(descriptors_paths
)))
225 for desc_path
in descriptors_paths
:
226 with
open(desc_path
) as descriptor_file
:
227 descriptor_data
= descriptor_file
.read()
230 desc_type
, descriptor_data
= validation_im
.yaml_validation(
231 self
, descriptor_data
233 self
._logger
.debug("desc_type: {}".format(desc_type
))
234 self
._logger
.debug("descriptor_data:\n{}".format(descriptor_data
))
235 self
._validator
.pyangbind_validation(desc_type
, descriptor_data
)
236 if not (desc_type
== "vnfd" or desc_type
== "nsd"):
239 "current type": desc_type
,
240 "new type": desc_type
,
248 new_desc_type
= desc_type
250 sol006_model
= yaml
.safe_dump(
251 im_translation
.translate_im_model_to_sol006(
255 default_flow_style
=False,
260 ) = self
._validator
.yaml_validation(sol006_model
)
261 self
._validator
.pyangbind_validation(
262 new_desc_type
, new_descriptor_data
265 with
open(desc_path
, "w") as descriptor_file
:
266 descriptor_file
.write(sol006_model
)
269 "current type": desc_type
,
270 "new type": new_desc_type
,
277 except ValidationException
as ve2
:
280 "current type": desc_type
,
281 "new type": new_desc_type
,
284 "translated": "ERROR",
285 "error": "Error in the post-validation: {}".format(
290 except Exception as e2
:
293 "current type": desc_type
,
294 "new type": new_desc_type
,
297 "translated": "ERROR",
298 "error": "Error in the translation: {}".format(str(e2
)),
301 except ValidationException
as ve
:
304 "current type": desc_type
,
309 "error": "Error in the pre-validation: {}".format(str(ve
)),
312 except Exception as e
:
315 "current type": desc_type
,
325 def descriptor_translate(self
, descriptor_file
):
327 **Translate input descriptor file from Rel EIGHT OSM to SOL006**
330 - base_directory is the root path for all packages
332 :return: YAML descriptor in the new format
334 self
._logger
.debug("")
335 with
open(descriptor_file
, "r") as df
:
336 im_model
= yaml
.safe_load(df
.read())
337 sol006_model
= im_translation
.translate_im_model_to_sol006(im_model
)
338 return yaml
.safe_dump(sol006_model
, indent
=4, default_flow_style
=False)
340 def build(self
, package_folder
, skip_validation
=False, skip_charm_build
=False):
342 **Creates a .tar.gz file given a package_folder**
345 - package_folder: is the name of the folder to be packaged
346 - skip_validation: is the flag to validate or not the descriptors on the folder before build
348 :returns: message result for the build process
350 self
._logger
.debug("")
351 package_folder
= package_folder
.rstrip("/")
352 if not os
.path
.exists("{}".format(package_folder
)):
353 return "Fail, package is not in the specified path"
354 if not skip_validation
:
355 print("Validating package {}".format(package_folder
))
356 results
= self
.validate(package_folder
, recursive
=False)
358 for result
in results
:
359 if result
["valid"] != "OK":
360 raise ClientException(
361 "There was an error validating the file {} with error: {}".format(
362 result
["path"], result
["error"]
365 print("Validation OK")
367 raise ClientException(
368 "No descriptor file found in: {}".format(package_folder
)
372 package_handling
.get_package_type(package_folder
)
373 != package_handling
.OSM_OLD
376 charm_list
= self
.build_all_charms(
377 package_folder
, skip_charm_build
, is_sol004_007
379 return self
.build_compressed_file(package_folder
, charm_list
, is_sol004_007
)
381 def calculate_checksum(self
, package_folder
):
383 **Function to calculate the checksum given a folder**
386 - package_folder: is the folder where we have the files to calculate the checksum
389 self
._logger
.debug("")
392 for f
in glob
.glob(package_folder
+ "/**/*.*", recursive
=True)
395 with
open("{}/checksums.txt".format(package_folder
), "w+") as checksum
:
396 for file_item
in files
:
397 if "checksums.txt" in file_item
:
399 checksum
.write("{}\t{}\n".format(utils
.md5(file_item
), file_item
))
401 def create_folders(self
, folders
, package_type
):
403 **Create folder given a list of folders**
406 - folders: [List] list of folders paths to be created
407 - package_type: is the type of package to be created
410 self
._logger
.debug("")
411 for folder
in folders
:
413 # print("Folder {} == package_type {}".format(folder[1], package_type))
414 if folder
[1] == package_type
:
415 print("Creating folder:\t{}".format(folder
[0]))
416 os
.makedirs(folder
[0])
417 except FileExistsError
:
420 def save_file(self
, file_name
, file_body
):
422 **Create a file given a name and the content**
425 - file_name: is the name of the file with the relative route
426 - file_body: is the content of the file
429 self
._logger
.debug("")
430 print("Creating file: \t{}".format(file_name
))
432 with
open(file_name
, "w+") as f
:
434 except Exception as e
:
435 raise ClientException(e
)
437 def generate_readme(self
):
439 **Creates the README content**
441 :returns: readme content
443 self
._logger
.debug("")
444 return """# Descriptor created by OSM descriptor package generated\n\n**Created on {} **""".format(
445 time
.strftime("%m/%d/%Y, %H:%M:%S", time
.localtime())
448 def generate_cloud_init(self
):
450 **Creates the cloud-init content**
452 :returns: cloud-init content
454 self
._logger
.debug("")
455 return "---\n#cloud-config"
457 def create_files(self
, files
, file_content
, package_type
):
459 **Creates the files given the file list and type**
462 - files: is the list of files structure
463 - file_content: is the content of the descriptor rendered by the template
464 - package_type: is the type of package to filter the creation structure
468 self
._logger
.debug("")
469 for file_item
, file_package
, file_type
in files
:
470 if package_type
== file_package
:
471 if file_type
== "descriptor":
472 self
.save_file(file_item
, file_content
)
473 elif file_type
== "readme":
474 self
.save_file(file_item
, self
.generate_readme())
475 elif file_type
== "cloud_init":
476 self
.save_file(file_item
, self
.generate_cloud_init())
478 def check_files_folders(self
, path_list
, override
):
480 **Find files and folders missing given a directory structure {"folders": [], "files": []}**
483 - path_list: is the list of files and folders to be created
484 - override: is the flag used to indicate the creation of the list even if the file exist to override it
486 :return: Missing paths Dict
488 self
._logger
.debug("")
492 for folder
in path_list
.get("folders"):
493 if not os
.path
.exists(folder
[0]):
494 folders
.append(folder
)
495 missing_paths
["folders"] = folders
497 for file_item
in path_list
.get("files"):
498 if not os
.path
.exists(file_item
[0]) or override
is True:
499 files
.append(file_item
)
500 missing_paths
["files"] = files
504 def build_all_charms(self
, package_folder
, skip_charm_build
, sol004_007
=True):
506 **Read the descriptor file, check that the charms referenced are in the folder and compiles them**
509 - packet_folder: is the location of the package
510 :return: Files and Folders not found. In case of override, it will return all file list
512 self
._logger
.debug("")
514 descriptor_file
= False
515 package_type
= package_handling
.get_package_type(package_folder
)
516 if sol004_007
and package_type
.find("TOSCA") >= 0:
517 descriptors_paths
= [
518 f
for f
in glob
.glob(package_folder
+ "/Definitions/*.yaml")
521 descriptors_paths
= [f
for f
in glob
.glob(package_folder
+ "/*.yaml")]
522 for file in descriptors_paths
:
523 if file.endswith("nfd.yaml"):
524 descriptor_file
= True
525 charms_set
= self
.charms_search(file, "vnf")
526 if file.endswith("nsd.yaml"):
527 descriptor_file
= True
528 charms_set
= self
.charms_search(file, "ns")
529 print("List of charms in the descriptor: {}".format(charms_set
))
530 if not descriptor_file
:
531 raise ClientException(
532 'Descriptor filename is not correct in: {}. It should end with "nfd.yaml" or "nsd.yaml"'.format(
536 if charms_set
and not skip_charm_build
:
537 for charmName
in charms_set
:
539 "{}/{}charms/layers/{}".format(
540 package_folder
, "Scripts/" if sol004_007
else "", charmName
544 "Building charm {}/{}charms/layers/{}".format(
545 package_folder
, "Scripts/" if sol004_007
else "", charmName
548 self
.charm_build(package_folder
, charmName
, sol004_007
)
549 print("Charm built: {}".format(charmName
))
551 "{}/{}charms/ops/{}".format(
552 package_folder
, "Scripts/" if sol004_007
else "", charmName
555 self
.charmcraft_build(package_folder
, charmName
)
557 if not os
.path
.isdir(
558 "{}/{}charms/{}".format(
559 package_folder
, "Scripts/" if sol004_007
else "", charmName
561 ) and not os
.path
.isfile(
562 "{}/{}charms/{}".format(
563 package_folder
, "Scripts/" if sol004_007
else "", charmName
566 raise ClientException(
567 "The charm: {} referenced in the descriptor file "
568 "is not present either in {}/charms or in {}/charms/layers".format(
569 charmName
, package_folder
, package_folder
572 self
._logger
.debug("Return list of charms: {}".format(charms_set
))
575 def discover_folder_structure(self
, base_directory
, name
, override
):
577 **Discover files and folders structure for SOL004/SOL007 descriptors given a base_directory and name**
580 - base_directory: is the location of the package to be created
581 - name: is the name of the package
582 - override: is the flag used to indicate the creation of the list even if the file exist to override it
583 :return: Files and Folders not found. In case of override, it will return all file list
585 self
._logger
.debug("")
586 prefix
= "{}/{}".format(base_directory
, name
)
589 ("{}_ns".format(prefix
), "ns"),
590 ("{}_ns/Licenses".format(prefix
), "ns"),
591 ("{}_ns/Files/icons".format(prefix
), "ns"),
592 ("{}_ns/Scripts/charms".format(prefix
), "ns"),
593 ("{}_vnf".format(name
), "vnf"),
594 ("{}_vnf/Licenses".format(prefix
), "vnf"),
595 ("{}_vnf/Scripts/charms".format(prefix
), "vnf"),
596 ("{}_vnf/Scripts/cloud_init".format(prefix
), "vnf"),
597 ("{}_vnf/Files/images".format(prefix
), "vnf"),
598 ("{}_vnf/Files/icons".format(prefix
), "vnf"),
599 ("{}_vnf/Scripts/scripts".format(prefix
), "vnf"),
600 ("{}_nst".format(prefix
), "nst"),
601 ("{}_nst/icons".format(prefix
), "nst"),
604 ("{}_ns/{}_nsd.yaml".format(prefix
, name
), "ns", "descriptor"),
605 ("{}_ns/README.md".format(prefix
), "ns", "readme"),
606 ("{}_vnf/{}_vnfd.yaml".format(prefix
, name
), "vnf", "descriptor"),
608 "{}_vnf/Scripts/cloud_init/cloud-config.txt".format(prefix
),
612 ("{}_vnf/README.md".format(prefix
), "vnf", "readme"),
613 ("{}_nst/{}_nst.yaml".format(prefix
, name
), "nst", "descriptor"),
614 ("{}_nst/README.md".format(prefix
), "nst", "readme"),
617 missing_files_folders
= self
.check_files_folders(files_folders
, override
)
618 # print("Missing files and folders: {}".format(missing_files_folders))
619 return missing_files_folders
621 def charm_build(self
, charms_folder
, build_name
, sol004_007
=True):
623 Build the charms inside the package.
624 params: package_folder is the name of the folder where is the charms to compile.
625 build_name is the name of the layer or interface
627 self
._logger
.debug("")
630 os
.environ
["JUJU_REPOSITORY"] = "{}/Scripts/charms".format(charms_folder
)
632 os
.environ
["JUJU_REPOSITORY"] = "{}/charms".format(charms_folder
)
634 os
.environ
["CHARM_LAYERS_DIR"] = "{}/layers".format(
635 os
.environ
["JUJU_REPOSITORY"]
637 os
.environ
["CHARM_INTERFACES_DIR"] = "{}/interfaces".format(
638 os
.environ
["JUJU_REPOSITORY"]
642 os
.environ
["CHARM_BUILD_DIR"] = "{}/Scripts/charms/builds".format(
646 os
.environ
["CHARM_BUILD_DIR"] = "{}/charms/builds".format(charms_folder
)
648 if not os
.path
.exists(os
.environ
["CHARM_BUILD_DIR"]):
649 os
.makedirs(os
.environ
["CHARM_BUILD_DIR"])
650 src_folder
= "{}/{}".format(os
.environ
["CHARM_LAYERS_DIR"], build_name
)
651 result
= subprocess
.run(["charm", "build", "{}".format(src_folder
)])
652 if result
.returncode
== 1:
653 raise ClientException("failed to build the charm: {}".format(src_folder
))
654 self
._logger
.verbose("charm {} built".format(src_folder
))
656 def charmcraft_build(self
, package_folder
, charm_name
):
658 Build the charms inside the package (new operator framework charms)
659 params: package_folder is the name of the folder where is the charms to compile.
660 build_name is the name of the layer or interface
662 self
._logger
.debug("Building charm {}".format(charm_name
))
663 src_folder
= f
"{package_folder}/Scripts/charms/ops/{charm_name}"
664 current_directory
= os
.getcwd()
667 result
= subprocess
.run(["charmcraft", "build"])
668 if result
.returncode
== 1:
669 raise ClientException(
670 "failed to build the charm: {}".format(src_folder
)
672 subprocess
.run(["rm", "-rf", f
"../../{charm_name}"])
673 subprocess
.run(["mv", "build", f
"../../{charm_name}"])
674 self
._logger
.verbose("charm {} built".format(src_folder
))
676 os
.chdir(current_directory
)
678 def build_compressed_file(self
, package_folder
, charm_list
=None, sol004_007
=True):
680 return self
.build_zipfile(package_folder
, charm_list
)
682 return self
.build_tarfile(package_folder
, charm_list
)
684 def build_zipfile(self
, package_folder
, charm_list
=None):
686 Creates a zip file given a package_folder
687 params: package_folder is the name of the folder to be packaged
690 self
._logger
.debug("")
693 directory_name
, package_name
= self
.create_temp_dir_sol004_007(
694 package_folder
, charm_list
697 os
.chdir(directory_name
)
698 package_type
= package_handling
.get_package_type(package_folder
)
702 package_handling
.SOL007
== package_type
703 or package_handling
.SOL007_TOSCA
== package_type
705 the_package
= SOL007Package(package_folder
)
707 package_handling
.SOL004
== package_type
708 or package_handling
.SOL004_TOSCA
== package_type
710 the_package
= SOL004Package(package_folder
)
712 raise ClientException(f
"Unknown package type: {package_type}")
714 the_package
.create_or_update_metadata_file()
716 the_zip_package
= shutil
.make_archive(
717 os
.path
.join(cwd
, package_name
),
719 os
.path
.join(directory_name
, package_name
),
722 print("Package created: {}".format(the_zip_package
))
724 return the_zip_package
726 except Exception as exc
:
727 raise ClientException(
728 "failure during build of zip file (create temp dir, calculate checksum, "
729 "zip file): {}".format(exc
)
734 shutil
.rmtree(os
.path
.join(package_folder
, "tmp"))
736 def build_tarfile(self
, package_folder
, charm_list
=None):
738 Creates a .tar.gz file given a package_folder
739 params: package_folder is the name of the folder to be packaged
740 returns: .tar.gz name
742 self
._logger
.debug("")
745 directory_name
, package_name
= self
.create_temp_dir(
746 package_folder
, charm_list
749 os
.chdir(directory_name
)
750 self
.calculate_checksum(package_name
)
751 with tarfile
.open("{}.tar.gz".format(package_name
), mode
="w:gz") as archive
:
752 print("Adding File: {}".format(package_name
))
753 archive
.add("{}".format(package_name
), recursive
=True)
754 # return "Created {}.tar.gz".format(package_folder)
755 # self.build("{}".format(os.path.basename(package_folder)))
758 created_package
= "{}/{}.tar.gz".format(
759 os
.path
.dirname(package_folder
) or ".", package_name
762 "{}/{}.tar.gz".format(directory_name
, package_name
), created_package
765 "{}/{}/checksums.txt".format(directory_name
, package_name
),
766 "{}/checksums.txt".format(package_folder
),
768 print("Package created: {}".format(created_package
))
769 return created_package
770 except Exception as exc
:
771 raise ClientException(
772 "failure during build of targz file (create temp dir, calculate checksum, "
773 "tar.gz file): {}".format(exc
)
778 shutil
.rmtree(os
.path
.join(package_folder
, "tmp"))
780 def create_temp_dir(self
, package_folder
, charm_list
=None):
782 Method to create a temporary folder where we can move the files in package_folder
784 self
._logger
.debug("")
785 ignore_patterns
= ".gitignore"
786 ignore
= shutil
.ignore_patterns(ignore_patterns
)
787 directory_name
= os
.path
.abspath(package_folder
)
788 package_name
= os
.path
.basename(directory_name
)
789 directory_name
+= "/tmp"
790 os
.makedirs("{}/{}".format(directory_name
, package_name
), exist_ok
=True)
791 self
._logger
.debug("Makedirs DONE: {}/{}".format(directory_name
, package_name
))
792 for item
in os
.listdir(package_folder
):
793 self
._logger
.debug("Item: {}".format(item
))
795 s
= os
.path
.join(package_folder
, item
)
796 d
= os
.path
.join(os
.path
.join(directory_name
, package_name
), item
)
799 os
.makedirs(d
, exist_ok
=True)
800 s_builds
= os
.path
.join(s
, "builds")
801 for charm
in charm_list
:
802 self
._logger
.debug("Copying charm {}".format(charm
))
803 if charm
in os
.listdir(s
):
804 s_charm
= os
.path
.join(s
, charm
)
805 elif charm
in os
.listdir(s_builds
):
806 s_charm
= os
.path
.join(s_builds
, charm
)
808 raise ClientException(
809 "The charm {} referenced in the descriptor file "
810 "could not be found in {}/charms or in {}/charms/builds".format(
811 charm
, package_folder
, package_folder
814 d_temp
= os
.path
.join(d
, charm
)
816 "Copying tree: {} -> {}".format(s_charm
, d_temp
)
818 if os
.path
.isdir(s_charm
):
820 s_charm
, d_temp
, symlinks
=True, ignore
=ignore
823 shutil
.copy2(s_charm
, d_temp
)
824 self
._logger
.debug("DONE")
826 self
._logger
.debug("Copying tree: {} -> {}".format(s
, d
))
827 shutil
.copytree(s
, d
, symlinks
=True, ignore
=ignore
)
828 self
._logger
.debug("DONE")
830 if item
in ignore_patterns
:
832 self
._logger
.debug("Copying file: {} -> {}".format(s
, d
))
834 self
._logger
.debug("DONE")
835 return directory_name
, package_name
837 def copy_tree(self
, s
, d
, ignore
):
838 self
._logger
.debug("Copying tree: {} -> {}".format(s
, d
))
839 shutil
.copytree(s
, d
, symlinks
=True, ignore
=ignore
)
840 self
._logger
.debug("DONE")
842 def create_temp_dir_sol004_007(self
, package_folder
, charm_list
=None):
844 Method to create a temporary folder where we can move the files in package_folder
846 self
._logger
.debug("")
847 ignore_patterns
= ".gitignore"
848 ignore
= shutil
.ignore_patterns(ignore_patterns
)
849 directory_name
= os
.path
.abspath(package_folder
)
850 package_name
= os
.path
.basename(directory_name
)
851 directory_name
+= "/tmp"
852 os
.makedirs("{}/{}".format(directory_name
, package_name
), exist_ok
=True)
853 self
._logger
.debug("Makedirs DONE: {}/{}".format(directory_name
, package_name
))
854 for item
in os
.listdir(package_folder
):
855 self
._logger
.debug("Item: {}".format(item
))
857 s
= os
.path
.join(package_folder
, item
)
858 d
= os
.path
.join(os
.path
.join(directory_name
, package_name
), item
)
860 if item
== "Scripts":
861 os
.makedirs(d
, exist_ok
=True)
863 for script_item
in os
.listdir(scripts_folder
):
864 scripts_destination_folder
= os
.path
.join(d
, script_item
)
865 if script_item
== "charms":
866 s_builds
= os
.path
.join(
867 scripts_folder
, script_item
, "builds"
869 for charm
in charm_list
:
870 self
._logger
.debug("Copying charm {}".format(charm
))
871 if charm
in os
.listdir(
872 os
.path
.join(scripts_folder
, script_item
)
874 s_charm
= os
.path
.join(
875 scripts_folder
, script_item
, charm
877 elif charm
in os
.listdir(s_builds
):
878 s_charm
= os
.path
.join(s_builds
, charm
)
880 raise ClientException(
881 "The charm {} referenced in the descriptor file "
882 "could not be found in {}/charms or in {}/charms/builds".format(
883 charm
, package_folder
, package_folder
886 d_temp
= os
.path
.join(
887 scripts_destination_folder
, charm
889 self
.copy_tree(s_charm
, d_temp
, ignore
)
892 os
.path
.join(scripts_folder
, script_item
),
893 scripts_destination_folder
,
897 self
.copy_tree(s
, d
, ignore
)
899 if item
in ignore_patterns
:
901 self
._logger
.debug("Copying file: {} -> {}".format(s
, d
))
903 self
._logger
.debug("DONE")
904 return directory_name
, package_name
906 def charms_search(self
, descriptor_file
, desc_type
):
908 "descriptor_file: {}, desc_type: {}".format(descriptor_file
, desc_type
)
911 with
open("{}".format(descriptor_file
)) as yaml_desc
:
912 descriptor_dict
= yaml
.safe_load(yaml_desc
)
913 # self._logger.debug("\n"+yaml.safe_dump(descriptor_dict, indent=4, default_flow_style=False))
918 "vnfd:vnfd-catalog" in descriptor_dict
919 or "vnfd-catalog" in descriptor_dict
924 "nsd:nsd-catalog" in descriptor_dict
925 or "nsd-catalog" in descriptor_dict
928 charms_set
= self
._charms
_search
_on
_osm
_im
_dict
(
929 descriptor_dict
, desc_type
932 if desc_type
== "ns":
933 get_charm_list
= self
._charms
_search
_on
_nsd
_sol
006_dict
934 elif desc_type
== "vnf":
935 get_charm_list
= self
._charms
_search
_on
_vnfd
_sol
006_dict
937 raise Exception("Bad descriptor type")
938 charms_set
= get_charm_list(descriptor_dict
)
941 def _charms_search_on_osm_im_dict(self
, osm_im_dict
, desc_type
):
942 self
._logger
.debug("")
944 for k1
, v1
in osm_im_dict
.items():
945 for k2
, v2
in v1
.items():
947 if "{}-configuration".format(desc_type
) in entry
:
948 vnf_config
= entry
["{}-configuration".format(desc_type
)]
949 for k3
, v3
in vnf_config
.items():
951 charms_set
.add((v3
["charm"]))
955 if "vdu-configuration" in vdu
:
956 for k4
, v4
in vdu
["vdu-configuration"].items():
958 charms_set
.add((v4
["charm"]))
961 def _charms_search_on_vnfd_sol006_dict(self
, sol006_dict
):
962 self
._logger
.debug("")
964 dfs
= sol006_dict
.get("vnfd", {}).get("df", [])
967 df
.get("lcm-operations-configuration", {})
968 .get("operate-vnf-op-config", {})
971 if day_1_2s
is not None:
972 for day_1_2
in day_1_2s
:
973 exec_env_list
= day_1_2
.get("execution-environment-list", [])
974 for exec_env
in exec_env_list
:
975 if "juju" in exec_env
and "charm" in exec_env
["juju"]:
976 charms_set
.add(exec_env
["juju"]["charm"])
979 def _charms_search_on_nsd_sol006_dict(self
, sol006_dict
):
980 self
._logger
.debug("")
982 nsd_list
= sol006_dict
.get("nsd", {}).get("nsd", [])
984 charm
= nsd
.get("ns-configuration", {}).get("juju", {}).get("charm")
986 charms_set
.add(charm
)