# Copyright 2016 - Nokia # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import collections import os import re import sys import yaml from collections import OrderedDict from oslo_log import log as logging from oslo_utils import uuidutils from tacker._i18n import _ from tacker.common import exceptions from tacker.common import log from tacker.common import utils from tacker.extensions import vnfm from tacker.plugins.common import constants from toscaparser import properties from toscaparser.utils import yamlparser FAILURE = 'tosca.policies.tacker.Failure' LOG = logging.getLogger(__name__) MONITORING = 'tosca.policies.Monitoring' SCALING = 'tosca.policies.Scaling' RESERVATION = 'tosca.policies.Reservation' PLACEMENT = 'tosca.policies.tacker.Placement' TACKERCP = 'tosca.nodes.nfv.CP.Tacker' TACKERVDU = 'tosca.nodes.nfv.VDU.Tacker' BLOCKSTORAGE = 'tosca.nodes.BlockStorage.Tacker' BLOCKSTORAGE_ATTACHMENT = 'tosca.nodes.BlockStorageAttachment' TOSCA_BINDS_TO = 'tosca.relationships.network.BindsTo' VDU = 'tosca.nodes.nfv.VDU' IMAGE = 'tosca.artifacts.Deployment.Image.VM' HEAT_SOFTWARE_CONFIG = 'OS::Heat::SoftwareConfig' OS_RESOURCES = { 'flavor': 'get_flavor_dict', 'image': 'get_image_dict' } FLAVOR_PROPS = { "num_cpus": ("vcpus", 1, None), "disk_size": ("disk", 1, "GB"), "mem_size": ("ram", 512, "MB") } CPU_PROP_MAP = (('hw:cpu_policy', 'cpu_affinity'), ('hw:cpu_threads_policy', 'thread_allocation'), ('hw:cpu_sockets', 'socket_count'), ('hw:cpu_threads', 'thread_count'), ('hw:cpu_cores', 'core_count')) CPU_PROP_VAL_MAP = {'cpu_affinity': ('shared', 'dedicated')} CPU_PROP_KEY_SET = {'cpu_affinity', 'thread_allocation', 'socket_count', 'thread_count', 'core_count'} FLAVOR_EXTRA_SPECS_LIST = ('cpu_allocation', 'mem_page_size', 'numa_node_count', 'numa_nodes') delpropmap = {TACKERVDU: ('mgmt_driver', 'config', 'service_type', 'placement_policy', 'monitoring_policy', 'metadata', 'failure_policy'), TACKERCP: ('management',)} convert_prop = {TACKERCP: {'anti_spoofing_protection': 'port_security_enabled', 'type': 'binding:vnic_type'}} convert_prop_values = {TACKERCP: {'type': {'sriov': 'direct', 'vnic': 'normal'}}} deletenodes = (MONITORING, FAILURE, PLACEMENT) HEAT_RESOURCE_MAP = { "flavor": "OS::Nova::Flavor", "image": "OS::Glance::WebImage" } SCALE_GROUP_RESOURCE = "OS::Heat::AutoScalingGroup" SCALE_POLICY_RESOURCE = "OS::Heat::ScalingPolicy" @log.log def updateimports(template): path = os.path.dirname(os.path.abspath(__file__)) + '/lib/' defsfile = path + 'tacker_defs.yaml' if 'imports' in template: template['imports'].append(defsfile) else: template['imports'] = [defsfile] if 'nfv' in template['tosca_definitions_version']: nfvfile = path + 'tacker_nfv_defs.yaml' template['imports'].append(nfvfile) LOG.debug(path) @log.log def check_for_substitution_mappings(template, params): sm_dict = params.get('substitution_mappings', {}) requirements = sm_dict.get('requirements') node_tpl = template['topology_template']['node_templates'] req_dict_tpl = template['topology_template']['substitution_mappings'].get( 'requirements') # Check if substitution_mappings and requirements are empty in params but # not in template. If True raise exception if (not sm_dict or not requirements) and req_dict_tpl: raise vnfm.InvalidParamsForSM() # Check if requirements are present for SM in template, if True then return elif (not sm_dict or not requirements) and not req_dict_tpl: return del params['substitution_mappings'] for req_name, req_val in (req_dict_tpl).items(): if req_name not in requirements: raise vnfm.SMRequirementMissing(requirement=req_name) if not isinstance(req_val, list): raise vnfm.InvalidSubstitutionMapping(requirement=req_name) try: node_name = req_val[0] node_req = req_val[1] node_tpl[node_name]['requirements'].append({ node_req: { 'node': requirements[req_name] } }) node_tpl[requirements[req_name]] = \ sm_dict[requirements[req_name]] except Exception: raise vnfm.InvalidSubstitutionMapping(requirement=req_name) @log.log def get_vdu_monitoring(template): monitoring_dict = dict() policy_dict = dict() policy_dict['vdus'] = collections.OrderedDict() for nt in template.nodetemplates: if nt.type_definition.is_derived_from(TACKERVDU): mon_policy = nt.get_property_value('monitoring_policy') or 'noop' if mon_policy != 'noop': if 'parameters' in mon_policy: mon_policy['monitoring_params'] = mon_policy['parameters'] policy_dict['vdus'][nt.name] = {} policy_dict['vdus'][nt.name][mon_policy['name']] = mon_policy if policy_dict.get('vdus'): monitoring_dict = policy_dict return monitoring_dict def get_vdu_applicationmonitoring(template): tpl_temp = "topology_template" n_temp = "node_templates" poly = "app_monitoring_policy" monitoring_dict = dict() policy_dict = dict() policy_dict['vdus'] = collections.OrderedDict() node_list = template[tpl_temp][n_temp].keys() for node in node_list: nt = template[tpl_temp][n_temp][node] if nt['type'] == TACKERVDU: if poly in nt['properties'].keys(): mon_policy = nt['properties'][poly] if mon_policy != 'noop': policy_dict['vdus'][node] = {} policy_dict['vdus'][node] = mon_policy del template[tpl_temp][n_temp][node]['properties'][poly] if policy_dict.get('vdus'): monitoring_dict = policy_dict return monitoring_dict @log.log def get_vdu_metadata(template, unique_id=None): metadata = dict() metadata.setdefault('vdus', {}) for nt in template.nodetemplates: if nt.type_definition.is_derived_from(TACKERVDU): metadata_dict = nt.get_property_value('metadata') or None if metadata_dict: metadata_dict['metering.server_group'] = \ (metadata_dict['metering.server_group'] + '-' + unique_id)[:15] metadata['vdus'][nt.name] = {} metadata['vdus'][nt.name].update(metadata_dict) return metadata @log.log def get_metadata_for_reservation(template, metadata): """Method used to add lease_id in metadata So that it can be used further while creating query_metadata :param template: ToscaTemplate object :param metadata: metadata dict :return: dictionary contains lease_id """ metadata.setdefault('reservation', {}) input_param_list = template.parsed_params.keys() # if lease_id is passed in the parameter file, # get it from template parsed_params. if 'lease_id' in input_param_list: metadata['reservation']['lease_id'] = template.parsed_params[ 'lease_id'] else: for policy in template.policies: if policy.entity_tpl['type'] == constants.POLICY_RESERVATION: metadata['reservation']['lease_id'] = policy.entity_tpl[ 'reservation']['properties']['lease_id'] break if not uuidutils.is_uuid_like(metadata['reservation']['lease_id']): raise exceptions.Invalid('Invalid UUID for lease_id') return metadata @log.log def pre_process_alarm_resources(vnf, template, vdu_metadata, unique_id=None): alarm_resources = dict() query_metadata = dict() alarm_actions = dict() for policy in template.policies: if policy.type_definition.is_derived_from(MONITORING): query_metadata.update(_process_query_metadata( vdu_metadata, policy, unique_id)) alarm_actions.update(_process_alarm_actions(vnf, policy)) if policy.type_definition.is_derived_from(RESERVATION): query_metadata.update(_process_query_metadata_reservation( vdu_metadata, policy)) alarm_actions.update(_process_alarm_actions_for_reservation( vnf, policy)) alarm_resources['event_types'] = { 'start_actions': {'event_type': 'lease.event.start_lease'}, 'before_end_actions': { 'event_type': 'lease.event.before_end_lease'}, 'end_actions': {'event_type': 'lease.event.end_lease'}} alarm_resources['query_metadata'] = query_metadata alarm_resources['alarm_actions'] = alarm_actions return alarm_resources def _process_query_metadata(metadata, policy, unique_id): query_mtdata = dict() triggers = policy.entity_tpl['triggers'] for trigger_name, trigger_dict in triggers.items(): resource_type = trigger_dict.get('condition').get('resource_type') # TODO(phuoc): currently, Tacker only supports resource_type with # instance value. Other types such as instance_network_interface, # instance_disk can be supported in the future. if resource_type == 'instance': if not (trigger_dict.get('metadata') and metadata): raise vnfm.MetadataNotMatched() is_matched = False for vdu_name, metadata_dict in metadata['vdus'].items(): trigger_dict['metadata'] = \ (trigger_dict['metadata'] + '-' + unique_id)[:15] if trigger_dict['metadata'] == \ metadata_dict['metering.server_group']: is_matched = True if not is_matched: raise vnfm.MetadataNotMatched() query_template = dict() query_template['str_replace'] = dict() query_template['str_replace']['template'] = \ '{"=": {"server_group": "scaling_group_id"}}' scaling_group_param = \ {'scaling_group_id': trigger_dict['metadata']} query_template['str_replace']['params'] = scaling_group_param else: raise vnfm.InvalidResourceType(resource_type=resource_type) query_mtdata[trigger_name] = query_template return query_mtdata def _process_query_metadata_reservation(metadata, policy): query_metadata = dict() policy_actions = policy.entity_tpl['reservation'].keys() policy_actions.remove('properties') for action in policy_actions: query_template = [{ "field": 'traits.lease_id', "op": "eq", "value": metadata['reservation']['lease_id']}] query_metadata[action] = query_template return query_metadata def _process_alarm_actions(vnf, policy): # process alarm url here triggers = policy.entity_tpl['triggers'] alarm_actions = dict() for trigger_name, trigger_dict in triggers.items(): alarm_url = vnf['attributes'].get(trigger_name) if alarm_url: alarm_url = str(alarm_url) LOG.debug('Alarm url in heat %s', alarm_url) alarm_actions[trigger_name] = dict() alarm_actions[trigger_name]['alarm_actions'] = [alarm_url] return alarm_actions def _process_alarm_actions_for_reservation(vnf, policy): # process alarm url here alarm_actions = dict() policy_actions = policy.entity_tpl['reservation'].keys() policy_actions.remove('properties') for action in policy_actions: alarm_url = vnf['attributes'].get(action) if alarm_url: LOG.debug('Alarm url in heat %s', alarm_url) alarm_actions[action] = dict() alarm_actions[action]['alarm_actions'] = [alarm_url] return alarm_actions def get_volumes(template): volume_dict = dict() node_tpl = template['topology_template']['node_templates'] for node_name in list(node_tpl.keys()): node_value = node_tpl[node_name] if node_value['type'] != BLOCKSTORAGE: continue volume_dict[node_name] = dict() block_properties = node_value.get('properties', {}) for prop_name, prop_value in block_properties.items(): if prop_name == 'size': prop_value = \ re.compile('(\d+)\s*(\w+)').match(prop_value).groups()[0] volume_dict[node_name][prop_name] = prop_value del node_tpl[node_name] return volume_dict @log.log def get_vol_attachments(template): vol_attach_dict = dict() node_tpl = template['topology_template']['node_templates'] valid_properties = { 'location': 'mountpoint' } for node_name in list(node_tpl.keys()): node_value = node_tpl[node_name] if node_value['type'] != BLOCKSTORAGE_ATTACHMENT: continue vol_attach_dict[node_name] = dict() vol_attach_properties = node_value.get('properties', {}) # parse properties for prop_name, prop_value in vol_attach_properties.items(): if prop_name in valid_properties: vol_attach_dict[node_name][valid_properties[prop_name]] = \ prop_value # parse requirements to get mapping of cinder volume <-> Nova instance for req in node_value.get('requirements', {}): if 'virtualBinding' in req: vol_attach_dict[node_name]['instance_uuid'] = \ {'get_resource': req['virtualBinding']['node']} elif 'virtualAttachment' in req: vol_attach_dict[node_name]['volume_id'] = \ {'get_resource': req['virtualAttachment']['node']} del node_tpl[node_name] return vol_attach_dict @log.log def get_block_storage_details(template): block_storage_details = dict() block_storage_details['volumes'] = get_volumes(template) block_storage_details['volume_attachments'] = get_vol_attachments(template) return block_storage_details @log.log def get_mgmt_ports(tosca): mgmt_ports = {} for nt in tosca.nodetemplates: if nt.type_definition.is_derived_from(TACKERCP): mgmt = nt.get_property_value('management') or None if mgmt: vdu = None for rel, node in nt.relationships.items(): if rel.is_derived_from(TOSCA_BINDS_TO): vdu = node.name break if vdu is not None: name = 'mgmt_ip-%s' % vdu mgmt_ports[name] = nt.name LOG.debug('mgmt_ports: %s', mgmt_ports) return mgmt_ports @log.log def add_resources_tpl(heat_dict, hot_res_tpl): for res, res_dict in (hot_res_tpl).items(): for vdu, vdu_dict in (res_dict).items(): res_name = vdu + "_" + res heat_dict["resources"][res_name] = { "type": HEAT_RESOURCE_MAP[res], "properties": {} } for prop, val in (vdu_dict).items(): # change from 'get_input' to 'get_param' to meet HOT template if isinstance(val, dict): if 'get_input' in val: val['get_param'] = val.pop('get_input') heat_dict["resources"][res_name]["properties"][prop] = val if heat_dict["resources"].get(vdu): heat_dict["resources"][vdu]["properties"][res] = { "get_resource": res_name } @log.log def convert_unsupported_res_prop(heat_dict, unsupported_res_prop): res_dict = heat_dict['resources'] for res, attr in (res_dict).items(): res_type = attr['type'] if res_type in unsupported_res_prop: prop_dict = attr['properties'] unsupported_prop_dict = unsupported_res_prop[res_type] unsupported_prop = set(prop_dict.keys()) & set( unsupported_prop_dict.keys()) for prop in unsupported_prop: # some properties are just punted to 'value_specs' # property if they are incompatible new_prop = unsupported_prop_dict[prop] if new_prop == 'value_specs': prop_dict.setdefault(new_prop, {})[ prop] = prop_dict.pop(prop) else: prop_dict[new_prop] = prop_dict.pop(prop) @log.log def represent_odict(dump, tag, mapping, flow_style=None): value = [] node = yaml.MappingNode(tag, value, flow_style=flow_style) if dump.alias_key is not None: dump.represented_objects[dump.alias_key] = node best_style = True if hasattr(mapping, 'items'): mapping = mapping.items() for item_key, item_value in mapping: node_key = dump.represent_data(item_key) node_value = dump.represent_data(item_value) if not (isinstance(node_key, yaml.ScalarNode) and not node_key.style): best_style = False if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style): best_style = False value.append((node_key, node_value)) if flow_style is None: if dump.default_flow_style is not None: node.flow_style = dump.default_flow_style else: node.flow_style = best_style return node @log.log def post_process_heat_template(heat_tpl, mgmt_ports, metadata, alarm_resources, res_tpl, vol_res={}, unsupported_res_prop=None, unique_id=None): # # TODO(bobh) - remove when heat-translator can support literal strings. # def fix_user_data(user_data_string): user_data_string = re.sub('user_data: #', 'user_data: |\n #', user_data_string, re.MULTILINE) return re.sub('\n\n', '\n', user_data_string, re.MULTILINE) heat_tpl = fix_user_data(heat_tpl) # # End temporary workaround for heat-translator # heat_dict = yamlparser.simple_ordered_parse(heat_tpl) for outputname, portname in mgmt_ports.items(): ipval = {'get_attr': [portname, 'fixed_ips', 0, 'ip_address']} output = {outputname: {'value': ipval}} if 'outputs' in heat_dict: heat_dict['outputs'].update(output) else: heat_dict['outputs'] = output LOG.debug('Added output for %s', outputname) if metadata.get('vdus'): for vdu_name, metadata_dict in metadata['vdus'].items(): metadata_dict['metering.server_group'] = \ (metadata_dict['metering.server_group'] + '-' + unique_id)[:15] if heat_dict['resources'].get(vdu_name): heat_dict['resources'][vdu_name]['properties']['metadata'] =\ metadata_dict query_metadata = alarm_resources.get('query_metadata') alarm_actions = alarm_resources.get('alarm_actions') event_types = alarm_resources.get('event_types') if query_metadata: for trigger_name, matching_metadata_dict in query_metadata.items(): if heat_dict['resources'].get(trigger_name): query_mtdata = dict() query_mtdata['query'] = \ query_metadata[trigger_name] heat_dict['resources'][trigger_name][ 'properties'].update(query_mtdata) if alarm_actions: for trigger_name, alarm_actions_dict in alarm_actions.items(): if heat_dict['resources'].get(trigger_name): heat_dict['resources'][trigger_name]['properties']. \ update(alarm_actions_dict) if event_types: for trigger_name, event_type in event_types.items(): if heat_dict['resources'].get(trigger_name): heat_dict['resources'][trigger_name]['properties'].update( event_type) add_resources_tpl(heat_dict, res_tpl) for res in heat_dict["resources"].values(): if not res['type'] == HEAT_SOFTWARE_CONFIG: continue config = res["properties"]["config"] if 'get_file' in config: res["properties"]["config"] = open(config["get_file"]).read() if vol_res.get('volumes'): add_volume_resources(heat_dict, vol_res) if unsupported_res_prop: convert_unsupported_res_prop(heat_dict, unsupported_res_prop) yaml.SafeDumper.add_representer(OrderedDict, lambda dumper, value: represent_odict(dumper, u'tag:yaml.org,2002:map', value)) return yaml.safe_dump(heat_dict) @log.log def add_volume_resources(heat_dict, vol_res): # Add cinder volumes for res_name, cinder_vol in vol_res['volumes'].items(): heat_dict['resources'][res_name] = { 'type': 'OS::Cinder::Volume', 'properties': {} } for prop_name, prop_val in cinder_vol.items(): heat_dict['resources'][res_name]['properties'][prop_name] = \ prop_val # Add cinder volume attachments for res_name, cinder_vol in vol_res['volume_attachments'].items(): heat_dict['resources'][res_name] = { 'type': 'OS::Cinder::VolumeAttachment', 'properties': {} } for prop_name, prop_val in cinder_vol.items(): heat_dict['resources'][res_name]['properties'][prop_name] = \ prop_val @log.log def post_process_template(template): def _add_scheduler_hints_property(nt): hints = nt.get_property_value('scheduler_hints') if hints is None: hints = OrderedDict() hints_schema = {'type': 'map', 'required': False, 'entry_schema': {'type': 'string'}} hints_prop = properties.Property('scheduler_hints', hints, hints_schema) nt.get_properties_objects().append(hints_prop) return hints for nt in template.nodetemplates: if (nt.type_definition.is_derived_from(MONITORING) or nt.type_definition.is_derived_from(FAILURE) or nt.type_definition.is_derived_from(PLACEMENT)): template.nodetemplates.remove(nt) continue if nt.type in delpropmap.keys(): for prop in delpropmap[nt.type]: for p in nt.get_properties_objects(): if prop == p.name: nt.get_properties_objects().remove(p) # change the property value first before the property key if nt.type in convert_prop_values: for prop in convert_prop_values[nt.type].keys(): for p in nt.get_properties_objects(): if (prop == p.name and p.value in convert_prop_values[nt.type][prop].keys()): v = convert_prop_values[nt.type][prop][p.value] p.value = v if nt.type in convert_prop: for prop in convert_prop[nt.type].keys(): for p in nt.get_properties_objects(): if prop == p.name: schema_dict = {'type': p.type} v = nt.get_property_value(p.name) newprop = properties.Property( convert_prop[nt.type][prop], v, schema_dict) nt.get_properties_objects().append(newprop) nt.get_properties_objects().remove(p) if nt.type_definition.is_derived_from(TACKERVDU): reservation_metadata = nt.get_property_value( 'reservation_metadata') if reservation_metadata is not None: hints = _add_scheduler_hints_property(nt) input_resource_type = reservation_metadata.get( 'resource_type') input_id = reservation_metadata.get('id') # Checking if 'resource_type' and 'id' is passed through a # input parameter file or not. If it's then get the value # from input parameter file. if (isinstance(input_resource_type, OrderedDict) and input_resource_type.get('get_input')): input_resource_type = template.parsed_params.get( input_resource_type.get('get_input')) # TODO(niraj-singh): Remove this validation once bug # 1815755 is fixed. if input_resource_type not in ( 'physical_host', 'virtual_instance'): raise exceptions.Invalid( 'resoure_type must be physical_host' ' or virtual_instance') if (isinstance(input_id, OrderedDict) and input_id.get('get_input')): input_id = template.parsed_params.get( input_id.get('get_input')) if input_resource_type == 'physical_host': hints['reservation'] = input_id elif input_resource_type == 'virtual_instance': hints['group'] = input_id nt.get_properties_objects().remove(nt.get_properties().get( 'reservation_metadata')) @log.log def get_mgmt_driver(template): mgmt_driver = None for nt in template.nodetemplates: if nt.type_definition.is_derived_from(TACKERVDU): if (mgmt_driver and nt.get_property_value('mgmt_driver') != mgmt_driver): raise vnfm.MultipleMGMTDriversSpecified() else: mgmt_driver = nt.get_property_value('mgmt_driver') return mgmt_driver def findvdus(template): vdus = [] for nt in template.nodetemplates: if nt.type_definition.is_derived_from(TACKERVDU): vdus.append(nt) return vdus def get_flavor_dict(template, flavor_extra_input=None): flavor_dict = {} vdus = findvdus(template) for nt in vdus: flavor_tmp = nt.get_properties().get('flavor') if flavor_tmp: continue if nt.get_capabilities().get("nfv_compute"): flavor_dict[nt.name] = {} properties = nt.get_capabilities()["nfv_compute"].get_properties() for prop, (hot_prop, default, unit) in \ (FLAVOR_PROPS).items(): hot_prop_val = (properties[prop].value if properties.get(prop, None) else None) if unit and hot_prop_val: hot_prop_val = \ utils.change_memory_unit(hot_prop_val, unit) flavor_dict[nt.name][hot_prop] = \ hot_prop_val if hot_prop_val else default if any(p in properties for p in FLAVOR_EXTRA_SPECS_LIST): flavor_dict[nt.name]['extra_specs'] = {} es_dict = flavor_dict[nt.name]['extra_specs'] populate_flavor_extra_specs(es_dict, properties, flavor_extra_input) return flavor_dict def populate_flavor_extra_specs(es_dict, properties, flavor_extra_input): if 'mem_page_size' in properties: mval = properties['mem_page_size'].value if str(mval).isdigit(): mval = mval * 1024 elif mval not in ('small', 'large', 'any'): raise vnfm.HugePageSizeInvalidInput( error_msg_details=(mval + ":Invalid Input")) es_dict['hw:mem_page_size'] = mval if 'numa_nodes' in properties and 'numa_node_count' in properties: LOG.warning('Both numa_nodes and numa_node_count have been ' 'specified; numa_node definitions will be ignored and ' 'numa_node_count will be applied') if 'numa_node_count' in properties: es_dict['hw:numa_nodes'] = \ properties['numa_node_count'].value if 'numa_nodes' in properties and 'numa_node_count' not in properties: nodes_dict = dict(properties['numa_nodes'].value) dval = list(nodes_dict.values()) ncount = 0 for ndict in dval: invalid_input = set(ndict.keys()) - {'id', 'vcpus', 'mem_size'} if invalid_input: raise vnfm.NumaNodesInvalidKeys( error_msg_details=(', '.join(invalid_input)), valid_keys="id, vcpus and mem_size") if 'id' in ndict and 'vcpus' in ndict: vk = "hw:numa_cpus." + str(ndict['id']) vval = ",".join([str(x) for x in ndict['vcpus']]) es_dict[vk] = vval if 'id' in ndict and 'mem_size' in ndict: mk = "hw:numa_mem." + str(ndict['id']) es_dict[mk] = ndict['mem_size'] ncount += 1 es_dict['hw:numa_nodes'] = ncount if 'cpu_allocation' in properties: cpu_dict = dict(properties['cpu_allocation'].value) invalid_input = set(cpu_dict.keys()) - CPU_PROP_KEY_SET if invalid_input: raise vnfm.CpuAllocationInvalidKeys( error_msg_details=(', '.join(invalid_input)), valid_keys=(', '.join(CPU_PROP_KEY_SET))) for(k, v) in CPU_PROP_MAP: if v not in cpu_dict: continue if CPU_PROP_VAL_MAP.get(v, None): if cpu_dict[v] not in CPU_PROP_VAL_MAP[v]: raise vnfm.CpuAllocationInvalidValues( error_msg_details=cpu_dict[v], valid_values=CPU_PROP_VAL_MAP[v]) es_dict[k] = cpu_dict[v] if flavor_extra_input: es_dict.update(flavor_extra_input) def get_image_dict(template): image_dict = {} vdus = findvdus(template) for vdu in vdus: if not vdu.entity_tpl.get("artifacts"): continue artifacts = vdu.entity_tpl["artifacts"] for name, artifact in (artifacts).items(): if ('type' in artifact.keys() and artifact["type"] == IMAGE): if 'file' not in artifact.keys(): raise vnfm.FilePathMissing() image_dict[vdu.name] = { "location": artifact["file"], "container_format": "bare", "disk_format": "raw", "name": name } return image_dict def get_resources_dict(template, flavor_extra_input=None): res_dict = dict() for res, method in (OS_RESOURCES).items(): res_method = getattr(sys.modules[__name__], method) if res is 'flavor': res_dict[res] = res_method(template, flavor_extra_input) else: res_dict[res] = res_method(template) return res_dict @log.log def get_scaling_policy(template): scaling_policy_names = list() for policy in template.policies: if (policy.type_definition.is_derived_from(SCALING)): scaling_policy_names.append(policy.name) return scaling_policy_names @log.log def get_scaling_group_dict(ht_template, scaling_policy_names): scaling_group_dict = dict() scaling_group_names = list() heat_dict = yamlparser.simple_ordered_parse(ht_template) for resource_name, resource_dict in heat_dict['resources'].items(): if resource_dict['type'] == SCALE_GROUP_RESOURCE: scaling_group_names.append(resource_name) if scaling_group_names: scaling_group_dict[scaling_policy_names[0]] = scaling_group_names[0] return scaling_group_dict def get_nested_resources_name(template): for policy in template.policies: if (policy.type_definition.is_derived_from(SCALING)): nested_resource_name = policy.name + '_res.yaml' return nested_resource_name def get_sub_heat_tmpl_name(template): for policy in template.policies: if (policy.type_definition.is_derived_from(SCALING)): sub_heat_tmpl_name = policy.name + '_' + \ uuidutils.generate_uuid() + '_res.yaml' return sub_heat_tmpl_name def update_nested_scaling_resources(nested_resources, mgmt_ports, metadata, res_tpl, unsupported_res_prop=None): nested_tpl = dict() if nested_resources: nested_resource_name, nested_resources_yaml =\ list(nested_resources.items())[0] nested_resources_dict =\ yamlparser.simple_ordered_parse(nested_resources_yaml) if metadata.get('vdus'): for vdu_name, metadata_dict in metadata['vdus'].items(): if nested_resources_dict['resources'].get(vdu_name): nested_resources_dict['resources'][vdu_name]['properties']['metadata'] = \ metadata_dict add_resources_tpl(nested_resources_dict, res_tpl) for res in nested_resources_dict["resources"].values(): if not res['type'] == HEAT_SOFTWARE_CONFIG: continue config = res["properties"]["config"] if 'get_file' in config: res["properties"]["config"] = open(config["get_file"]).read() if unsupported_res_prop: convert_unsupported_res_prop(nested_resources_dict, unsupported_res_prop) for outputname, portname in mgmt_ports.items(): ipval = {'get_attr': [portname, 'fixed_ips', 0, 'ip_address']} output = {outputname: {'value': ipval}} if 'outputs' in nested_resources_dict: nested_resources_dict['outputs'].update(output) else: nested_resources_dict['outputs'] = output LOG.debug(_('Added output for %s'), outputname) yaml.SafeDumper.add_representer( OrderedDict, lambda dumper, value: represent_odict( dumper, u'tag:yaml.org,2002:map', value)) nested_tpl[nested_resource_name] =\ yaml.safe_dump(nested_resources_dict) return nested_tpl