diff options
Diffstat (limited to 'onap-client/onap_client/sdc/vnf.py')
-rw-r--r-- | onap-client/onap_client/sdc/vnf.py | 354 |
1 files changed, 235 insertions, 119 deletions
diff --git a/onap-client/onap_client/sdc/vnf.py b/onap-client/onap_client/sdc/vnf.py index da8f213..5fa401c 100644 --- a/onap-client/onap_client/sdc/vnf.py +++ b/onap-client/onap_client/sdc/vnf.py @@ -43,6 +43,8 @@ from onap_client.sdc import vsp from onap_client.util import utility import time +import random +import json vnf_client = SDCClient().sdc.vnf @@ -66,6 +68,30 @@ class VNF(Resource): "nested": { "vm_type": {"type": str, "required": True}, "properties": {"type": dict, "required": True, "default": {}}, + "resources": { + "type": list, + "list_item": dict, + "required": False, + "default": [], + "nested": { + "resource_name": {"type": str, "required": True}, + "resource_id": {"type": str, "required": False}, + "catalog_resource_name": {"type": str, "required": False}, + "origin_type": {"type": str, "required": False, "default": "VF"}, + "properties": {"type": dict, "required": False, "default": {}}, + "relationship": { + "type": dict, + "required": False, + "default": {}, + "nested": { + "relationship_type": {"type": str, "required": True}, + "requirement": {"type": str, "required": True}, + "requirement_id": {"type": str, "required": True}, + "properties": {"type": dict, "required": False, "default": {}}, + } + }, + }, + }, }, }, "network_roles": { @@ -94,6 +120,7 @@ class VNF(Resource): "properties": {"type": dict, "required": False, "default": {}}, }, }, + "allow_update": {"type": bool, "required": False, "default": False}, } def __init__( @@ -105,6 +132,7 @@ class VNF(Resource): vm_types=[], network_roles=[], policies=[], + allow_update=False, ): vnf_input = {} @@ -122,6 +150,7 @@ class VNF(Resource): vnf_input["vm_types"] = vm_types vnf_input["network_roles"] = network_roles vnf_input["policies"] = policies + vnf_input["allow_update"] = allow_update super().__init__(vnf_input) @@ -129,8 +158,11 @@ class VNF(Resource): """Creates a vnf object in SDC""" vnf = None - if get_vnf_id(vnf_input.get("vnf_name")) is None: + existing = get_vnf_id(vnf_input.get("vnf_name")) + if not existing: vnf = create_vnf(vnf_input) + elif vnf_input.get("allow_update"): + vnf = update_vnf(existing, vnf_input) else: raise exceptions.ResourceAlreadyExistsException( "VNF resource {} already exists".format(vnf_input.get("vnf_name")) @@ -149,39 +181,18 @@ class VNF(Resource): for vm_type in vm_types: vm_type_tag = vm_type.get("vm_type") properties = vm_type.get("properties") + resources = vm_type.get("resources", []) instance_ids = instance_ids_for_property(model, "vm_type_tag", vm_type_tag) for instance_id in instance_ids: - for k, v in properties.items(): - # updating vm_type properties - self.add_instance_property(instance_id, k, v) - vm_type_instances.append(instance_id) - for network_role in network_roles: - # checking if abstract node has matching network role, - # and updating if found - nrt = network_role.get("network_role_tag") - nr = network_role.get("network_role") - related_networks = network_role.get("related_networks") - instance_property = network_role_property_for_instance( - nrt, model, instance_id - ) - if instance_property: - self.add_instance_property(instance_id, instance_property, nr) - if related_networks: - property_val = [ - {"related_network_role": related_network_role} - for related_network_role in related_networks - ] - rnr_instance_property = instance_property.replace( - "_network_role", "_related_networks" - ) - self.add_instance_property( - instance_id, - rnr_instance_property, - str(property_val).replace("'", '\\"'), - ) + vm_type_instances.append(instance_id) + self._add_instance_properties(instance_id, properties) + self._add_resources(instance_id, resources) + self._add_vm_type_network_role(instance_id, network_roles) for policy in policies: policy_name = policy.get("policy_name") + if self.policy_exists(policy_name): + continue policy_model = self.add_policy_resource(policy_name) self.associate_policy(policy_model.catalog_resource_id, vm_type_instances) for k, v in policy.get("properties", {}).items(): @@ -190,6 +201,115 @@ class VNF(Resource): for k, v in inputs.items(): self.add_input_value(k, v) + def _add_instance_properties(self, instance_id, properties_dict): + for k, v in properties_dict.items(): + # updating vm_type properties + self.add_instance_property(instance_id, k, v) + + def _add_resources(self, instance_id, resources_dict): + for resource in resources_dict: + resource_name = resource.get("resource_name") + + if self.resource_exists(resource_name): + continue + + catalog_resource_name = resource.get("catalog_resource_name") + resource_id = resource.get("resource_id") + resource_origin = resource.get("origin_type") + resource_relationship = resource.get("relationship", {}) + + if not resource_id: + resource_id = get_vnf_id(catalog_resource_name) + if not resource_id: + raise exceptions.ResourceIDNotFoundException( + "resource ID was not passed, and resource lookup by name was not found {}".format( + resource_name + ) + ) + new_resource = add_resource(self.catalog_resource_id, resource_id, resource_name, origin_type=resource_origin) + new_resource_id = new_resource["id"] + if resource_relationship: + relationship_type = resource_relationship.get("relationship_type") + relationship_requirement = resource_relationship.get("requirement") + relationship_requirement_id = resource_relationship.get("requirement_id") + self.add_resource_relationship(new_resource_id, instance_id, relationship_type, relationship_requirement, relationship_requirement_id) + for k, v in resource_relationship.get("properties", {}).items(): + self.add_instance_property_non_vf(new_resource_id, k, v, origin_section="componentInstancesProperties") + + def add_resource_relationship(self, from_node, to_node, relationship_type, relationship_requirement, relationship_requirement_id): + components = self.tosca.get("componentInstances", []) + for component in components: + if component.get("uniqueId") == to_node: + capabilities = component.get("capabilities", {}).get(relationship_type, []) + for capability in capabilities: + capability_owner_id = capability.get("ownerId") + capability_name = capability.get("name") + capability_uid = capability.get("uniqueId") + + return vnf_client.add_resource_relationship( + **self.attributes, + from_node_resource_id=from_node, + to_node_resource_id=to_node, + relationship_type=relationship_type, + capability_name=capability_name, + capability_owner_id=capability_owner_id, + capability_id=capability_uid, + requirement_name=relationship_requirement, + requirement_id=relationship_requirement_id, + ) + + def _add_vm_type_network_role(self, instance_id, network_roles_dict): + model = self.tosca + for network_role in network_roles_dict: + # checking if abstract node has matching network role, + # and updating if found + nrt = network_role.get("network_role_tag") + nr = network_role.get("network_role") + related_networks = network_role.get("related_networks") + instance_property = network_role_property_for_instance( + nrt, model, instance_id + ) + if instance_property: + self.add_instance_property(instance_id, instance_property, nr) + if related_networks: + property_val = [ + {"related_network_role": related_network_role} + for related_network_role in related_networks + ] + rnr_instance_property = instance_property.replace( + "_network_role", "_related_networks" + ) + self.add_instance_property( + instance_id, + rnr_instance_property, + str(property_val).replace("'", '\\"'), + ) + + def resource_exists(self, resource_name): + """Checking the tosca model for a VF to see if a resource + has already been added""" + + component_instances = self.tosca.get("componentInstances", []) + + for component in component_instances: + if component.get("name") == resource_name: + return True + + return False + + def policy_exists(self, policy_name): + """Checking the tosca model for a VF to see if a resource + has already been added""" + + policies = self.tosca.get("policies", {}) + + for p_name, policy in policies.items(): + tosca_policy_name = policy.get("name").lower() + if tosca_policy_name.find("{}..{}".format(self.vnf_name.lower(), policy_name.lower())) != -1: + return True + + return False + def _submit(self): """Submits the vnf in SDC""" certification = vnf_client.certify_catalog_resource( @@ -202,34 +322,6 @@ class VNF(Resource): self.attributes["catalog_resource_name"] = vnf.catalog_resource_name self.attributes["tosca"] = vnf.response_data - def add_resource( - self, catalog_resource_id, catalog_resource_name, origin_type="VF" - ): - """Attaches a resource to a VNF in SDC - - :catalog_resource_id: ID of a resource in the SDC catalog - :catalog_resource_name: name to give to the resource when attaching to vnf - :origin_type: specifies the origin of the attached resource - - """ - milli_timestamp = int(time.time() * 1000) - - resource_instance = vnf_client.add_resource_instance( - **self.attributes, - posX=306, - posY=248, - milli_timestamp=milli_timestamp, - new_catalog_resource_id=catalog_resource_id, - new_catalog_resource_name=catalog_resource_name, - originType=origin_type, - ) - - response = { - "id": resource_instance.catalog_resource_instance_id, - "tosca": resource_instance.response_data, - } - self.attributes[catalog_resource_name] = response - def add_input_value(self, input_name, input_default_value): """Updates an input value on a VNF @@ -262,7 +354,7 @@ class VNF(Resource): # instance, policy, and group properties can probably be merged # rn there is a lot of dup - def add_instance_property(self, instance_id, property_name, property_value): + def add_instance_property(self, instance_id, property_name, property_value, origin_section="componentInstancesInputs"): """Updates an instance property on a abstract instance attached to a VNF :instance_id: ID of a instance attached to a VNF @@ -272,7 +364,7 @@ class VNF(Resource): """ self._refresh() - instance_inputs = self.tosca.get("componentInstancesInputs", {}).get( + instance_inputs = self.tosca.get(origin_section, {}).get( instance_id, {} ) @@ -301,97 +393,82 @@ class VNF(Resource): ) ) - def add_policy_property(self, policy_id, property_name, property_value): - """Updates a policy property on a polic attached to a VNF + def add_instance_property_non_vf(self, instance_id, property_name, property_value, origin_section="componentInstancesProperties"): + """Updates an instance property on a abstract instance attached to a VNF - :policy_id: ID of a policy attached to a VNF + :instance_id: ID of a instance attached to a VNF :property_name: property name to update :property_value: value to update property with """ self._refresh() - policies = ( - self.tosca.get("policies", {}).get(policy_id, {}).get("properties", {}) + instance_inputs = self.tosca.get(origin_section, {}).get( + instance_id, {} ) - for prop in policies: + for prop in instance_inputs: if prop.get("name") == property_name: unique_id = prop.get("uniqueId") + parent_unique_id = prop.get("parentUniqueId") + owner_id = prop.get("ownerId") + schemaType = prop.get("schemaType", "") property_type = prop.get("type") - description = prop.get("description") - return vnf_client.add_catalog_policy_property( + return vnf_client.add_catalog_resource_property_non_vf( **self.attributes, unique_id=unique_id, - catalog_policy_id=policy_id, + parent_unique_id=parent_unique_id, + owner_id=owner_id, + catalog_resource_instance_id=instance_id, property_name=property_name, property_default_value=property_value, - description=description, + schema_type=schemaType, property_type=property_type, ) raise exceptions.PropertyNotFoundException( - "Property {} was not found in policy {}".format(property_name, policy_id) + "Property {} was not found in Instance {}".format( + property_name, instance_id + ) ) - def add_group_property(self, group_id, property_name, property_value): - """Updates a group property on a group attached to a VNF + def add_policy_property(self, policy_id, property_name, property_value): + """Updates a policy property on a polic attached to a VNF - :group_id: ID of a group attached to a VNF + :policy_id: ID of a policy attached to a VNF :property_name: property name to update :property_value: value to update property with """ self._refresh() - groups = self.tosca.get("groups", []) - - for group in groups: - if group.get("uniqueId") == group_id: - properties = group.get("properties", []) - for prop in properties: - unique_id = prop.get("uniqueId") - property_type = prop.get("type") - description = prop.get("description") - parent_unique_id = prop.get("parentUniqueId") - owner_id = prop.get("ownerId") - return vnf_client.add_catalog_group_property( - **self.attributes, - unique_id=unique_id, - catalog_group_id=group_id, - property_name=property_name, - property_default_value=property_value, - description=description, - property_type=property_type, - parent_unique_id=parent_unique_id, - owner_id=owner_id, - ) - - raise exceptions.PropertyNotFoundException( - "Property {} was not found in group {}".format(property_name, group_id) + policies = ( + self.tosca.get("policies", {}).get(policy_id, {}).get("properties", {}) ) - def add_group_resource(self, group_name): - """Adds an SDC group resource to a VNF - - :group_name: name of the group, matching onap-client.conf - - """ - sdc_properties = sdc.SDC_PROPERTIES - group = sdc_properties.GROUPS.get(group_name) - if not group: - raise exceptions.UnknownGroupException( - "Group {} was not found in configuration file".format(group_name) - ) + for prop in policies: + if prop.get("name") == property_name: + unique_id = prop.get("uniqueId") + property_type = prop.get("type") + description = prop.get("description") + return vnf_client.add_catalog_policy_property( + **self.attributes, + unique_id=unique_id, + catalog_policy_id=policy_id, + property_name=property_name, + property_default_value=property_value, + description=description, + property_type=property_type, + ) - return vnf_client.add_catalog_resource_group( - **self.attributes, catalog_group_name=group + raise exceptions.PropertyNotFoundException( + "Property {} was not found in policy {}".format(property_name, policy_id) ) def add_policy_resource(self, policy_name): """Adds an SDC policy resource to a VNF - :group_name: name of the policy, matching onap-client.conf + :policy_name: name of the policy, matching onap-client.conf """ sdc_properties = sdc.SDC_PROPERTIES @@ -417,18 +494,30 @@ class VNF(Resource): **self.attributes, catalog_policy_id=policy_id, instance_ids=instance_ids ) - def associate_group(self, group_id, instance_id): - """associates an SDC group resource to an VNF instance resource""" - return vnf_client.add_group_to_instance( - **self.attributes, catalog_group_id=group_id, instance_id=instance_id - ) - def _refresh(self): """GETs the VNF model from SDC and updates the VNF object""" vnf = vnf_client.get_catalog_resource(**self.attributes) self.attributes["tosca"] = vnf.response_data +def update_vnf(catalog_resource_id, vnf_input): + vnf = vnf_client.checkout_catalog_resource(catalog_resource_id=catalog_resource_id).response_data + + new_vnf_metadata = vnf_client.get_catalog_resource_metadata(catalog_resource_id=vnf.get("uniqueId")).response_data.get("metadata", {}) + + csar_version = vsp.get_vsp_version_id(vnf.get("csarUUID"), search_key="name") + + vnf["csarVersion"] = csar_version + vnf["componentMetadata"] = new_vnf_metadata + + updated_vnf = vnf_client.update_catalog_resource(catalog_resource_id=vnf.get("uniqueId"), payload_data=json.dumps(vnf)).response_data + + vnf_input["catalog_resource_id"] = updated_vnf.get("uniqueId") + vnf_input["tosca"] = updated_vnf + + return vnf_input + + def create_vnf(vnf_input): """Creates a vnf object in SDC @@ -490,6 +579,33 @@ def network_role_property_for_instance(network_role_tag, vnf_model, instance_id) return None +def add_resource(parent_resource_id, catalog_resource_id, catalog_resource_name, origin_type="VF"): + """Attaches a resource to a VNF in SDC + + :catalog_resource_id: ID of a resource in the SDC catalog + :catalog_resource_name: name to give to the resource when attaching to vnf + :origin_type: specifies the origin of the attached resource + + """ + milli_timestamp = int(time.time() * 1000) + + resource_instance = vnf_client.add_resource_instance( + catalog_resource_id=parent_resource_id, + posX=random.randrange(150, 550), # nosec + posY=random.randrange(150, 450), # nosec + milli_timestamp=milli_timestamp, + new_catalog_resource_id=catalog_resource_id, + new_catalog_resource_name=catalog_resource_name, + originType=origin_type, + ) + + response = { + "id": resource_instance.catalog_resource_instance_id, + "tosca": resource_instance.response_data, + } + return response + + @utility def get_vnf(vnf_name): """Queries SDC for the TOSCA model for a VNF""" |