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 the_package
.create_or_update_metadata_file()
714 the_zip_package
= shutil
.make_archive(
715 os
.path
.join(cwd
, package_name
),
717 os
.path
.join(directory_name
, package_name
),
720 print("Package created: {}".format(the_zip_package
))
722 return the_zip_package
724 except Exception as exc
:
725 raise ClientException(
726 "failure during build of zip file (create temp dir, calculate checksum, "
727 "zip file): {}".format(exc
)
732 shutil
.rmtree(os
.path
.join(package_folder
, "tmp"))
734 def build_tarfile(self
, package_folder
, charm_list
=None):
736 Creates a .tar.gz file given a package_folder
737 params: package_folder is the name of the folder to be packaged
738 returns: .tar.gz name
740 self
._logger
.debug("")
743 directory_name
, package_name
= self
.create_temp_dir(
744 package_folder
, charm_list
747 os
.chdir(directory_name
)
748 self
.calculate_checksum(package_name
)
749 with tarfile
.open("{}.tar.gz".format(package_name
), mode
="w:gz") as archive
:
750 print("Adding File: {}".format(package_name
))
751 archive
.add("{}".format(package_name
), recursive
=True)
752 # return "Created {}.tar.gz".format(package_folder)
753 # self.build("{}".format(os.path.basename(package_folder)))
756 created_package
= "{}/{}.tar.gz".format(
757 os
.path
.dirname(package_folder
) or ".", package_name
760 "{}/{}.tar.gz".format(directory_name
, package_name
), created_package
763 "{}/{}/checksums.txt".format(directory_name
, package_name
),
764 "{}/checksums.txt".format(package_folder
),
766 print("Package created: {}".format(created_package
))
767 return created_package
768 except Exception as exc
:
769 raise ClientException(
770 "failure during build of targz file (create temp dir, calculate checksum, "
771 "tar.gz file): {}".format(exc
)
776 shutil
.rmtree(os
.path
.join(package_folder
, "tmp"))
778 def create_temp_dir(self
, package_folder
, charm_list
=None):
780 Method to create a temporary folder where we can move the files in package_folder
782 self
._logger
.debug("")
783 ignore_patterns
= ".gitignore"
784 ignore
= shutil
.ignore_patterns(ignore_patterns
)
785 directory_name
= os
.path
.abspath(package_folder
)
786 package_name
= os
.path
.basename(directory_name
)
787 directory_name
+= "/tmp"
788 os
.makedirs("{}/{}".format(directory_name
, package_name
), exist_ok
=True)
789 self
._logger
.debug("Makedirs DONE: {}/{}".format(directory_name
, package_name
))
790 for item
in os
.listdir(package_folder
):
791 self
._logger
.debug("Item: {}".format(item
))
793 s
= os
.path
.join(package_folder
, item
)
794 d
= os
.path
.join(os
.path
.join(directory_name
, package_name
), item
)
797 os
.makedirs(d
, exist_ok
=True)
798 s_builds
= os
.path
.join(s
, "builds")
799 for charm
in charm_list
:
800 self
._logger
.debug("Copying charm {}".format(charm
))
801 if charm
in os
.listdir(s
):
802 s_charm
= os
.path
.join(s
, charm
)
803 elif charm
in os
.listdir(s_builds
):
804 s_charm
= os
.path
.join(s_builds
, charm
)
806 raise ClientException(
807 "The charm {} referenced in the descriptor file "
808 "could not be found in {}/charms or in {}/charms/builds".format(
809 charm
, package_folder
, package_folder
812 d_temp
= os
.path
.join(d
, charm
)
814 "Copying tree: {} -> {}".format(s_charm
, d_temp
)
816 if os
.path
.isdir(s_charm
):
818 s_charm
, d_temp
, symlinks
=True, ignore
=ignore
821 shutil
.copy2(s_charm
, d_temp
)
822 self
._logger
.debug("DONE")
824 self
._logger
.debug("Copying tree: {} -> {}".format(s
, d
))
825 shutil
.copytree(s
, d
, symlinks
=True, ignore
=ignore
)
826 self
._logger
.debug("DONE")
828 if item
in ignore_patterns
:
830 self
._logger
.debug("Copying file: {} -> {}".format(s
, d
))
832 self
._logger
.debug("DONE")
833 return directory_name
, package_name
835 def copy_tree(self
, s
, d
, ignore
):
836 self
._logger
.debug("Copying tree: {} -> {}".format(s
, d
))
837 shutil
.copytree(s
, d
, symlinks
=True, ignore
=ignore
)
838 self
._logger
.debug("DONE")
840 def create_temp_dir_sol004_007(self
, package_folder
, charm_list
=None):
842 Method to create a temporary folder where we can move the files in package_folder
844 self
._logger
.debug("")
845 ignore_patterns
= ".gitignore"
846 ignore
= shutil
.ignore_patterns(ignore_patterns
)
847 directory_name
= os
.path
.abspath(package_folder
)
848 package_name
= os
.path
.basename(directory_name
)
849 directory_name
+= "/tmp"
850 os
.makedirs("{}/{}".format(directory_name
, package_name
), exist_ok
=True)
851 self
._logger
.debug("Makedirs DONE: {}/{}".format(directory_name
, package_name
))
852 for item
in os
.listdir(package_folder
):
853 self
._logger
.debug("Item: {}".format(item
))
855 s
= os
.path
.join(package_folder
, item
)
856 d
= os
.path
.join(os
.path
.join(directory_name
, package_name
), item
)
858 if item
== "Scripts":
859 os
.makedirs(d
, exist_ok
=True)
861 for script_item
in os
.listdir(scripts_folder
):
862 scripts_destination_folder
= os
.path
.join(d
, script_item
)
863 if script_item
== "charms":
864 s_builds
= os
.path
.join(
865 scripts_folder
, script_item
, "builds"
867 for charm
in charm_list
:
868 self
._logger
.debug("Copying charm {}".format(charm
))
869 if charm
in os
.listdir(
870 os
.path
.join(scripts_folder
, script_item
)
872 s_charm
= os
.path
.join(
873 scripts_folder
, script_item
, charm
875 elif charm
in os
.listdir(s_builds
):
876 s_charm
= os
.path
.join(s_builds
, charm
)
878 raise ClientException(
879 "The charm {} referenced in the descriptor file "
880 "could not be found in {}/charms or in {}/charms/builds".format(
881 charm
, package_folder
, package_folder
884 d_temp
= os
.path
.join(
885 scripts_destination_folder
, charm
887 self
.copy_tree(s_charm
, d_temp
, ignore
)
890 os
.path
.join(scripts_folder
, script_item
),
891 scripts_destination_folder
,
895 self
.copy_tree(s
, d
, ignore
)
897 if item
in ignore_patterns
:
899 self
._logger
.debug("Copying file: {} -> {}".format(s
, d
))
901 self
._logger
.debug("DONE")
902 return directory_name
, package_name
904 def charms_search(self
, descriptor_file
, desc_type
):
906 "descriptor_file: {}, desc_type: {}".format(descriptor_file
, desc_type
)
909 with
open("{}".format(descriptor_file
)) as yaml_desc
:
910 descriptor_dict
= yaml
.safe_load(yaml_desc
)
911 # self._logger.debug("\n"+yaml.safe_dump(descriptor_dict, indent=4, default_flow_style=False))
916 "vnfd:vnfd-catalog" in descriptor_dict
917 or "vnfd-catalog" in descriptor_dict
922 "nsd:nsd-catalog" in descriptor_dict
923 or "nsd-catalog" in descriptor_dict
926 charms_set
= self
._charms
_search
_on
_osm
_im
_dict
(
927 descriptor_dict
, desc_type
930 if desc_type
== "ns":
931 get_charm_list
= self
._charms
_search
_on
_nsd
_sol
006_dict
932 elif desc_type
== "vnf":
933 get_charm_list
= self
._charms
_search
_on
_vnfd
_sol
006_dict
935 raise Exception("Bad descriptor type")
936 charms_set
= get_charm_list(descriptor_dict
)
939 def _charms_search_on_osm_im_dict(self
, osm_im_dict
, desc_type
):
940 self
._logger
.debug("")
942 for k1
, v1
in osm_im_dict
.items():
943 for k2
, v2
in v1
.items():
945 if "{}-configuration".format(desc_type
) in entry
:
946 vnf_config
= entry
["{}-configuration".format(desc_type
)]
947 for k3
, v3
in vnf_config
.items():
949 charms_set
.add((v3
["charm"]))
953 if "vdu-configuration" in vdu
:
954 for k4
, v4
in vdu
["vdu-configuration"].items():
956 charms_set
.add((v4
["charm"]))
959 def _charms_search_on_vnfd_sol006_dict(self
, sol006_dict
):
960 self
._logger
.debug("")
962 dfs
= sol006_dict
.get("vnfd", {}).get("df", [])
965 df
.get("lcm-operations-configuration", {})
966 .get("operate-vnf-op-config", {})
969 if day_1_2s
is not None:
970 for day_1_2
in day_1_2s
:
971 exec_env_list
= day_1_2
.get("execution-environment-list", [])
972 for exec_env
in exec_env_list
:
973 if "juju" in exec_env
and "charm" in exec_env
["juju"]:
974 charms_set
.add(exec_env
["juju"]["charm"])
977 def _charms_search_on_nsd_sol006_dict(self
, sol006_dict
):
978 self
._logger
.debug("")
980 nsd_list
= sol006_dict
.get("nsd", {}).get("nsd", [])
982 charm
= nsd
.get("ns-configuration", {}).get("juju", {}).get("charm")
984 charms_set
.add(charm
)