def _validate_instantiation_levels(policy, instantiation_levels): expected_policy_type = [ 'tosca.policies.nfv.VduInstantiationLevels', 'tosca.policies.nfv.' 'VirtualLinkInstantiationLevels' ] for policy_name, policy_tpl in policy.items(): if policy_tpl.get('type') not in expected_policy_type: return if not instantiation_levels: msg = ('Policy of type' ' "tosca.policies.nfv.InstantiationLevels is not defined.') raise exceptions.InvalidCSAR(msg) if policy_tpl.get('properties'): levels_in_policy = policy_tpl.get('properties').get('levels') if levels_in_policy: invalid_levels = set( levels_in_policy.keys()) - set(instantiation_levels) else: invalid_levels = set() if invalid_levels: error_msg = "Level(s) {} not found in defined levels" \ " {}".format(",".join(sorted(invalid_levels)), ",".join(sorted(instantiation_levels) )) raise exceptions.InvalidCSAR(error_msg)
def _validate_sw_image_data_for_artifact(node_tpl, template_name): artifact_type = [] artifacts = node_tpl.get('artifacts') if artifacts: for key, value in artifacts.items(): if value.get('type') == 'tosca.artifacts.nfv.SwImage': artifact_type.append(value.get('type')) if len(artifact_type) > 1: error_msg = ('artifacts of type "tosca.artifacts.nfv.SwImage"' ' is added more than one time for' ' node %(node)s.') % { 'node': template_name } raise exceptions.InvalidCSAR(error_msg) if artifact_type and node_tpl.get('properties'): if not node_tpl.get('properties').get('sw_image_data'): error_msg = ('Node property "sw_image_data" is missing for' ' artifact type %(type)s for ' 'node %(node)s.') % { 'type': artifact_type[0], 'node': template_name } raise exceptions.InvalidCSAR(error_msg)
def _validate_sw_image_data_for_artifact(node_tpl, template_name): artifact_names = [] artifacts = node_tpl.get('artifacts') if not artifacts: return for key, value in artifacts.items(): if isinstance(value, dict): if value.get('type') == 'tosca.artifacts.nfv.SwImage': artifact_names.append(key) elif isinstance(value, str): artifact_names.append(key) if len(artifact_names) > 1: error_msg = ('artifacts of type "tosca.artifacts.nfv.SwImage"' ' is added more than one time for' ' node %(node)s.') % { 'node': template_name } raise exceptions.InvalidCSAR(error_msg) if artifact_names and node_tpl.get('properties'): if not node_tpl.get('properties').get('sw_image_data'): error_msg = ('Node property "sw_image_data" is missing for' ' artifact %(artifact_name)s for node %(node)s.') % { 'artifact_name': artifact_names[0], 'node': template_name } raise exceptions.InvalidCSAR(error_msg)
def _get_data_from_csar(tosca, context, id): for tp in tosca.nested_tosca_templates_with_topology: policies = tp.tpl.get("policies") if policies: levels = _get_instantiation_levels_from_policy(policies) for policy_tpl in policies: _validate_instantiation_levels(policy_tpl, levels) _validate_sw_image_data_for_artifacts(tosca) vnf_data = _get_vnf_data(tosca.nodetemplates) if not vnf_data: error_msg = "VNF properties are mandatory" raise exceptions.InvalidCSAR(error_msg) flavours = _populate_flavour_data(tosca) if not flavours: error_msg = "No VNF flavours are available" raise exceptions.InvalidCSAR(error_msg) csar = CSAR(tosca.input_path, tosca.a_file) vnf_artifacts = [] if csar.validate(): vnf_artifacts = _get_vnf_artifacts(csar) return vnf_data, flavours, vnf_artifacts
def _convert_artifacts(vnf_artifacts, artifacts_data, csar): artifacts_data_split = re.split(b'\n\n+', artifacts_data) for data in artifacts_data_split: if re.findall(b'.?Name:.?|.?Source:.?|', data): # validate key's existence if re.findall(b'.?Algorithm:.?|.?Hash:.?', data): artifact_data_dict = yaml.safe_load(data) if 'Name' in artifact_data_dict.keys(): artifact_data_dict.update( {"Source": artifact_data_dict.pop("Name")}) if 'Content-Type' in artifact_data_dict.keys(): del artifact_data_dict['Content-Type'] if sorted(ARTIFACT_KEYS) != sorted(artifact_data_dict.keys()): missing_key = list( set(ARTIFACT_KEYS) ^ set(artifact_data_dict.keys())) missing_key = sorted(missing_key) invalid_artifact_err_msg = \ (('One of the artifact information ' 'may not have the key("%(key)s")') % {'key': missing_key}) raise exceptions.InvalidCSAR(invalid_artifact_err_msg) # validate value's existence for key, value in artifact_data_dict.items(): if not value: invalid_artifact_err_msg = \ (('One of the artifact information may not have ' 'the key value("%(key)s")') % {'key': key}) raise exceptions.InvalidCSAR(invalid_artifact_err_msg) artifact_path = artifact_data_dict.get('Source') if os.path.splitext(artifact_path)[-1][1:] \ in IMAGE_FORMAT_LIST: continue else: algorithm = artifact_data_dict.get('Algorithm') hash_code = artifact_data_dict.get('Hash') result = _validate_hash(algorithm, hash_code, csar, artifact_path) if result: vnf_artifacts.append(artifact_data_dict) else: invalid_artifact_err_msg = \ (('The hash "%(hash)s" of artifact file ' '"%(artifact)s" is an invalid value.') % {'hash': hash_code, 'artifact': artifact_path}) raise exceptions.InvalidCSAR(invalid_artifact_err_msg) return vnf_artifacts
def load_csar_data(context, package_uuid, zip_path): extract_zip_path = os.path.join(CONF.vnf_package.vnf_package_csar_path, package_uuid) _extract_csar_zip_file(zip_path, extract_zip_path) try: tosca = ToscaTemplate(zip_path, None, True) return _get_data_from_csar(tosca, context, package_uuid) except exceptions.InvalidCSAR as exp: with excutils.save_and_reraise_exception(): LOG.error( "Error processing CSAR file %(path)s for vnf package" " %(uuid)s: Error: %(error)s. ", { 'path': zip_path, 'uuid': package_uuid, 'error': encodeutils.exception_to_unicode(exp) }) except Exception as exp: with excutils.save_and_reraise_exception(): LOG.error( "Tosca parser failed for vnf package %(uuid)s: " "Error: %(error)s. ", { 'uuid': package_uuid, 'error': encodeutils.exception_to_unicode(exp) }) exp.reraise = False raise exceptions.InvalidCSAR(encodeutils.exception_to_unicode(exp))
def _get_flavour_data(tp, flavours): sw_image_list = [] # Setting up flavour data flavour_id = tp.substitution_mappings.properties.get('flavour_id') if flavour_id: if isinstance(flavour_id, dict): error_msg = "flavour_id should be string and given" \ " {}".format(flavour_id) raise exceptions.InvalidCSAR(error_msg) flavour = {'flavour_id': flavour_id} else: flavour = {} instantiation_levels = _get_instantiation_levels(tp.policies) if instantiation_levels: flavour.update({'instantiation_levels': instantiation_levels}) for template_name, node_tpl in tp.tpl.get('node_templates').items(): # check the flavour property in vnf data _update_flavour_data_from_vnf(tp.custom_defs, node_tpl, flavour) # Update the software image data sw_image = _get_software_image(tp.custom_defs, template_name, node_tpl) if sw_image: sw_image_list.append(sw_image) # Add software images for flavour if sw_image_list: flavour.update({'sw_images': sw_image_list}) if flavour: flavours.append(flavour)
def _get_vnf_artifacts(csar): vnf_artifacts = [] if csar.is_tosca_metadata: if csar._get_metadata("ETSI-Entry-Manifest"): manifest_path = csar._get_metadata("ETSI-Entry-Manifest") if manifest_path.lower().endswith(".mf"): manifest_data = csar.zfile.read(manifest_path) vnf_artifacts = _convert_artifacts(vnf_artifacts, manifest_data, csar) else: invalid_manifest_err_msg = ( ('The file "%(manifest)s" in the CSAR "%(csar)s" does not ' 'contain valid manifest.') % { 'manifest': manifest_path, 'csar': csar.path }) raise exceptions.InvalidCSAR(invalid_manifest_err_msg) tosca_data = csar.zfile.read(TOSCA_META) vnf_artifacts = _convert_artifacts(vnf_artifacts, tosca_data, csar) else: filelist = csar.zfile.namelist() main_template_file_name = os.path.splitext( csar.main_template_file_name)[0] for path in filelist: if path.lower().endswith(".mf"): manifest_file_name = os.path.splitext(path)[0] if manifest_file_name == main_template_file_name: manifest_data = csar.zfile.read(path) vnf_artifacts = _convert_artifacts(vnf_artifacts, manifest_data, csar) else: invalid_manifest_err_msg = \ (('The filename "%(manifest)s" is an invalid name.' 'The name must be the same as the main template ' 'file name.') % {'manifest': path}) raise exceptions.InvalidCSAR(invalid_manifest_err_msg) # Deduplication vnf_artifacts = [ dict(t) for t in set([tuple(d.items()) for d in vnf_artifacts]) ] return vnf_artifacts
def _validate_hash(algorithm, hash_code, csar, artifact_path): z = zipfile.ZipFile(csar.path) algorithm = algorithm.lower() # validate Algorithm's value if algorithm in HASH_DICT.keys(): hash_obj = HASH_DICT[algorithm]() else: invalid_artifact_err_msg = (('The algorithm("%(algorithm)s") of ' 'artifact("%(artifact_path)s") is ' 'an invalid value.') % { 'algorithm': algorithm, 'artifact_path': artifact_path }) raise exceptions.InvalidCSAR(invalid_artifact_err_msg) filelist = csar.zfile.namelist() # validate Source's value if artifact_path in filelist: hash_obj.update(z.read(artifact_path)) elif ((urlparse(artifact_path).scheme == 'file') or (bool(urlparse(artifact_path).scheme) and bool(urlparse(artifact_path).netloc))): hash_obj.update(urllib2.urlopen(artifact_path).read()) else: invalid_artifact_err_msg = (('The path("%(artifact_path)s") of ' 'artifact Source is an invalid value.') % { 'artifact_path': artifact_path }) raise exceptions.InvalidCSAR(invalid_artifact_err_msg) # validate Hash's value if hash_code == hash_obj.hexdigest(): return True else: return False
def _get_instantiation_levels_from_policy(tpl_policies): """Get defined instantiation levels Getting instantiation levels defined under policy type 'tosca.policies.nfv.InstantiationLevels'. """ levels = [] for policy in tpl_policies: for key, value in policy.items(): if value.get('type') == 'tosca.policies.nfv.InstantiationLevels'\ and value.get('properties', {}).get('levels', {}): levels = value.get('properties').get('levels').keys() default_level = value.get('properties').get('default_level') if default_level and default_level not in levels: error_msg = "Level {} not found in defined levels" \ " {}".format(default_level, ",".join(sorted(levels))) raise exceptions.InvalidCSAR(error_msg) return levels