diff options
author | Sreeja Gattagouni <sg00744975@techmahindra.com> | 2023-05-19 07:20:37 +0000 |
---|---|---|
committer | Lukasz Rajewski <lukasz.rajewski@t-mobile.pl> | 2023-05-25 10:34:45 +0000 |
commit | 3860bac3bf74c485eebb0327e9125d6b45685278 (patch) | |
tree | fdce842bbf15f9ffcb4b549cb46b06515abdf4cb | |
parent | 676cfced1bf3b1602e99288f20ae1d3e91031f49 (diff) |
Addition-Deletion PNF Support in Automation(Macro-Flow)
-PNF Additon Support
-PNF Deletion Support
Issue-ID: INT-2211
Change-ID:I73f97f986a817d423f92f8d925dcd0947b8a2525
Signed-off-by: Sreeja Gattagouni <sg00744975@techmahindra.com>
-rw-r--r-- | integration_tests/test_07_instantiation.py | 170 | ||||
-rw-r--r-- | src/onapsdk/so/instantiation.py | 186 | ||||
-rwxr-xr-x | src/onapsdk/so/templates/instantiate_pnf_macro.json.j2 | 121 | ||||
-rwxr-xr-x | src/onapsdk/so/templates/instantiate_pnf_macro_so_pnf.json.j2 | 117 | ||||
-rw-r--r-- | tests/test_so_instantiation.py | 174 |
5 files changed, 765 insertions, 3 deletions
diff --git a/integration_tests/test_07_instantiation.py b/integration_tests/test_07_instantiation.py index c6cbc85..8fbb22d 100644 --- a/integration_tests/test_07_instantiation.py +++ b/integration_tests/test_07_instantiation.py @@ -21,10 +21,10 @@ from onapsdk.exceptions import StatusError from onapsdk.aai.business import Customer, ServiceInstance from onapsdk.aai.cloud_infrastructure import CloudRegion from onapsdk.configuration import settings -from onapsdk.sdc.service import Service, Vnf, VfModule +from onapsdk.sdc.service import Service, Vnf, VfModule, Pnf from onapsdk.so.deletion import ServiceDeletionRequest, VfModuleDeletionRequest, VnfDeletionRequest from onapsdk.so.instantiation import (ServiceInstantiation, SoService, - VfModuleInstantiation, VnfInstantiation, InstantiationParameter, + VfModuleInstantiation, VnfInstantiation, PnfInstantiation, InstantiationParameter, VfmoduleParameters, VnfParameters) @@ -303,6 +303,79 @@ def test_instantiate_macro(mock_service_components, mock_service_vnfs): assert service_deletion_request.status == ServiceDeletionRequest.StatusEnum.COMPLETED assert len(list(service_subscription.service_instances)) == 0 +@patch.object(Service, "pnfs", new_callable=PropertyMock) +@patch.object(Service, "components", new_callable=PropertyMock) +@pytest.mark.integration +def test_instantiate_macro_for_pnf(mock_service_components, mock_service_pnfs): + requests.get(f"{ServiceInstantiation.base_url}/reset") + requests.get(f"{Customer.base_url}/reset") + requests.post(f"{ServiceInstantiation.base_url}/set_aai_mock", json={"AAI_MOCK": settings.AAI_URL}) + + customer = Customer.create(global_customer_id="test_global_customer_id", + subscriber_name="test_subscriber_name", + subscriber_type="test_subscriber_type") + service = Service("test_service") + service._tosca_template = "n/a" + + mock_service_pnfs.return_value = [ + Pnf( + name="test_pnf", + node_template_type="pnf", + model_name= "test_pnf_model", + model_version_id = str(uuid4()), + model_invariant_id=str(uuid4()), + model_version="1.0", + model_customization_id=str(uuid4()), + model_instance_name=str(uuid4()), + component=MagicMock(), + ) + ] + service.unique_uuid = str(uuid4()) + service.identifier = str(uuid4()) + service.name = str(uuid4()) + customer.subscribe_service("service_type") + service_subscription = customer.get_service_subscription_by_service_type("service_type") + cloud_region = CloudRegion.create( + "test_owner", "test_cloud_region", orchestration_disabled=True, in_maint=False + ) + cloud_region.add_tenant( + tenant_id="test_tenant_name", tenant_name="test_tenant_name", tenant_context="test_tenant_context" + ) + tenant = cloud_region.get_tenant(tenant_id="test_tenant_name") + service_subscription.link_to_cloud_region_and_tenant(cloud_region=cloud_region, tenant=tenant) + owning_entity = "test_owning_entity" + project = "test_project" + line_of_business = "test_line_of_business" + platform = "test_platform" + + # Service instantiation + service._distributed = True + assert len(list(service_subscription.service_instances)) == 0 + service_instantiation_request = ServiceInstantiation.instantiate_macro( + sdc_service=service, + customer=customer, + owning_entity=owning_entity, + project=project, + line_of_business=line_of_business, + platform=platform, + cloud_region=cloud_region, + tenant=tenant, + service_subscription=service_subscription + ) + assert service_instantiation_request.status == ServiceInstantiation.StatusEnum.IN_PROGRESS + time.sleep(2) # After 1 second mocked server changed request status to complete + assert service_instantiation_request.status == ServiceInstantiation.StatusEnum.COMPLETED + assert len(list(service_subscription.service_instances)) == 1 + service_instance = next(service_subscription.service_instances) + + # Cleanup + with patch.object(ServiceInstance, "sdc_service", return_value=service) as service_mock: + service_deletion_request = service_instance.delete() + assert service_deletion_request.status == ServiceDeletionRequest.StatusEnum.IN_PROGRESS + time.sleep(2) # After 1 second mocked server changed request status to complete + assert service_deletion_request.status == ServiceDeletionRequest.StatusEnum.COMPLETED + assert len(list(service_subscription.service_instances)) == 0 + @patch.object(Service, "vnfs", new_callable=PropertyMock) @patch.object(Service, "components", new_callable=PropertyMock) @pytest.mark.integration @@ -425,3 +498,96 @@ def test_instantiate_macro_multiple_vnf(mock_service_components, mock_service_vn time.sleep(2) # After 1 second mocked server changed request status to complete assert service_deletion_request.status == ServiceDeletionRequest.StatusEnum.COMPLETED assert len(list(service_subscription.service_instances)) == 0 + +@patch.object(Service, "pnfs", new_callable=PropertyMock) +@patch.object(Service, "components", new_callable=PropertyMock) +@pytest.mark.integration +def test_instantiate_macro_multiple_pnf(mock_service_components, mock_service_pnfs): + requests.get(f"{ServiceInstantiation.base_url}/reset") + requests.get(f"{Customer.base_url}/reset") + requests.post(f"{ServiceInstantiation.base_url}/set_aai_mock", json={"AAI_MOCK": settings.AAI_URL}) + + customer = Customer.create(global_customer_id="test_global_customer_id", + subscriber_name="test_subscriber_name", + subscriber_type="test_subscriber_type") + service = Service("test_service") + service._tosca_template = "n/a" + + mock_service_pnfs.return_value = [ + Pnf( + name="test_pnf", + node_template_type="pnf", + model_name= "test_pnf_model", + model_version_id = str(uuid4()), + model_invariant_id=str(uuid4()), + model_version="1.0", + model_customization_id=str(uuid4()), + model_instance_name=str(uuid4()), + component=MagicMock(), + ) + ] + service.unique_uuid = str(uuid4()) + service.identifier = str(uuid4()) + service.name = str(uuid4()) + customer.subscribe_service("service_type") + service_subscription = customer.get_service_subscription_by_service_type("service_type") + cloud_region = CloudRegion.create( + "test_owner", "test_cloud_region", orchestration_disabled=True, in_maint=False + ) + cloud_region.add_tenant( + tenant_id="test_tenant_name", tenant_name="test_tenant_name", tenant_context="test_tenant_context" + ) + tenant = cloud_region.get_tenant(tenant_id="test_tenant_name") + service_subscription.link_to_cloud_region_and_tenant(cloud_region=cloud_region, tenant=tenant) + owning_entity = "test_owning_entity" + project = "test_project" + line_of_business = "test_line_of_business" + platform = "test_platform" + + so_service = SoService.load({ + "subscription_service_type": "service_type", + "pnfs": [ + { + "model_name": "test_pnf_model", + "instance_name": "pnf0", + "parameters": { + "param1": "value1" + }, + }, + { + "model_name": "test_pnf_model", + "instance_name": "pnf1", + "parameters": { + "param2": "value2" + }, + } + ] + }) + + # Service instantiation + service._distributed = True + assert len(list(service_subscription.service_instances)) == 0 + service_instantiation_request = ServiceInstantiation.instantiate_macro( + sdc_service=service, + customer=customer, + owning_entity=owning_entity, + project=project, + line_of_business=line_of_business, + platform=platform, + cloud_region=cloud_region, + tenant=tenant, + so_service=so_service + ) + assert service_instantiation_request.status == ServiceInstantiation.StatusEnum.IN_PROGRESS + time.sleep(2) # After 1 second mocked server changed request status to complete + assert service_instantiation_request.status == ServiceInstantiation.StatusEnum.COMPLETED + assert len(list(service_subscription.service_instances)) == 1 + service_instance = next(service_subscription.service_instances) + + # Cleanup + with patch.object(ServiceInstance, "sdc_service", return_value=service) as service_mock: + service_deletion_request = service_instance.delete() + assert service_deletion_request.status == ServiceDeletionRequest.StatusEnum.IN_PROGRESS + time.sleep(2) # After 1 second mocked server changed request status to complete + assert service_deletion_request.status == ServiceDeletionRequest.StatusEnum.COMPLETED + assert len(list(service_subscription.service_instances)) == 0 diff --git a/src/onapsdk/so/instantiation.py b/src/onapsdk/so/instantiation.py index c1bf10e..8130b00 100644 --- a/src/onapsdk/so/instantiation.py +++ b/src/onapsdk/so/instantiation.py @@ -24,7 +24,7 @@ from onapsdk.exceptions import ( ) from onapsdk.onap_service import OnapService from onapsdk.sdnc import NetworkPreload, VfModulePreload -from onapsdk.sdc.service import Network, Service as SdcService, Vnf, VfModule +from onapsdk.sdc.service import Network, Service as SdcService, Vnf, Pnf, VfModule from onapsdk.utils.jinja import jinja_env from onapsdk.utils.headers_creator import headers_so_creator from onapsdk.configuration import settings @@ -657,6 +657,190 @@ class VnfInstantiation(NodeTemplateInstantiation): # pylint: disable=too-many-a vnf=vnf_instance ) +class PnfInstantiation(NodeTemplateInstantiation): # pylint: disable=too-many-ancestors + """PNF instantiation class.""" + + def __init__(self, # pylint: disable=too-many-arguments + name: str, + request_id: str, + instance_id: str, + line_of_business: str, + platform: str, + pnf: Pnf) -> None: + """Class PnfInstantion object initialization. + + Args: + name (str): PNF name + request_id (str): request ID + instance_id (str): instance ID + service_instantiation ([type]): ServiceInstantiation class object + line_of_business (str): LineOfBusiness name + platform (str): Platform name + pnf (Pnf): Pnf class object + """ + super().__init__(name, request_id, instance_id, line_of_business, platform) + self.pnf = pnf + + @classmethod + def create_from_request_response(cls, request_response: dict) -> "PnfInstantiation": + """Create PNF instantiation object based on request details. + + Raises: + ResourceNotFound: Service related with given object doesn't exist + ResourceNotFound: No ServiceInstantiation related with given PNF instantiation + ResourceNotFound: PNF related with given object doesn't exist + InvalidResponse: Invalid dictionary - couldn't create PnfInstantiation object + + Returns: + PnfInstantiation: PnfInstantiation object + + """ + if request_response.get("request", {}).get("requestScope") == "pnf" and \ + request_response.get("request", {}).get("requestType") == "createInstance": + service: SdcService = None + for related_instance in request_response.get("request", {}).get("requestDetails", {})\ + .get("relatedInstanceList", []): + if related_instance.get("relatedInstance", {}).get("modelInfo", {})\ + .get("modelType") == "service": + service = SdcService(related_instance.get("relatedInstance", {})\ + .get("modelInfo", {}).get("modelName")) + if not service: + raise ResourceNotFound("No related service in Pnf instance details response") + pnf: Pnf = None + for service_pnf in service.pnfs: + if service_pnf.name == request_response.get("request", {})\ + .get("requestDetails", {}).get("modelInfo", {}).get("modelCustomizationName"): + pnf: Pnf = service_pnf + break + else: + raise ResourceNotFound("No pnf in service pnfs list") + return cls( + name=request_response.get("request", {})\ + .get("instanceReferences", {}).get("pnfInstanceName"), + request_id=request_response.get("request", {}).get("requestId"), + instance_id=request_response.get("request", {})\ + .get("instanceReferences", {}).get("pnfInstanceId"), + line_of_business=request_response.get("request", {})\ + .get("requestDetails", {}).get("lineOfBusiness", {}).get("lineOfBusinessName"), + platform=request_response.get("request", {})\ + .get("requestDetails", {}).get("platform", {}).get("platformName"), + pnf=pnf + ) + raise InvalidResponse("Invalid pnf instantions in response dictionary's requestList") + + @classmethod + def get_by_pnf_instance_name(cls, pnf_instance_name: str) -> "PnfInstantiation": + """Get PNF instantiation request by instance name. + + Raises: + InvalidResponse: Pnf instance with given name does not contain + requestList or the requestList does not contain any details. + + Returns: + PnfInstantiation: Pnf instantiation request object + + """ + response: dict = cls.send_message_json( + "GET", + f"Check {pnf_instance_name} service instantiation status", + (f"{cls.base_url}/onap/so/infra/orchestrationRequests/{cls.api_version}?" + f"filter=pnfInstanceName:EQUALS:{pnf_instance_name}"), + headers=headers_so_creator(OnapService.headers) + ) + key = "requestList" + if not response.get(key, []): + raise InvalidResponse(f"{key} of a Pnf instance is missing.") + for details in response[key]: + return cls.create_from_request_response(details) + msg = f"No details available in response dictionary's {key}." + raise InvalidResponse(msg) + + @classmethod + def instantiate_macro(cls, # pylint: disable=too-many-arguments, too-many-locals + aai_service_instance: "ServiceInstance", + pnf_object: "Pnf", + line_of_business: str, + platform: str, + cloud_region: "CloudRegion", + tenant: "Tenant", + sdc_service: "SdcService", + pnf_instance_name: str = None, + pnf_parameters: Iterable["InstantiationParameter"] = None, + so_pnf: "SoServicePnf" = None + ) -> "PnfInstantiation": + """Instantiate Pnf using macro method. + + Args: + aai_service_instance (ServiceInstance): Service instance associated with request + pnf_object (Pnf): Pnf to instantiate + line_of_business (LineOfBusiness): LineOfBusiness to use in instantiation request + platform (Platform): Platform to use in instantiation request + cloud_region (CloudRegion): Cloud region to use in instantiation request. + tenant (Tenant): Tenant to use in instantiation request. + pnf_instance_name (str, optional): Pnf instance name. Defaults to None. + pnf_parameters (Iterable[InstantiationParameter], optional): Instantiation parameters + that are sent in the request. Defaults to None + so_pnf (SoServicePnf): object with pnf instance parameters + + + Returns: + PnfInstantiation: PnfInstantiation object + + """ + owning_entity_id = None + project = settings.PROJECT + + for relationship in aai_service_instance.relationships: + if relationship.related_to == "owning-entity": + owning_entity_id = relationship.relationship_data.pop().get("relationship-value") + if relationship.related_to == "project": + project = relationship.relationship_data.pop().get("relationship-value") + + owning_entity = OwningEntity.get_by_owning_entity_id( + owning_entity_id=owning_entity_id) + + if so_pnf: + template_file = "instantiate_pnf_macro_so_pnf.json.j2" + if so_pnf.instance_name: + pnf_instance_name = so_pnf.instance_name + else: + template_file = "instantiate_pnf_macro.json.j2" + if pnf_instance_name is None: + pnf_instance_name = \ + f"Python_ONAP_SDK_pnf_instance_{str(uuid4())}" + + response: dict = cls.send_message_json( + "POST", + (f"Instantiate {sdc_service.name} " + f"service pnf {pnf_object.name}"), + (f"{cls.base_url}/onap/so/infra/serviceInstantiation/{cls.api_version}/" + f"serviceInstances/{aai_service_instance.instance_id}/pnfs"), + data=jinja_env().get_template(template_file).render( + instance_name=pnf_instance_name, + pnf=pnf_object, + service=sdc_service, + cloud_region=cloud_region or \ + next(aai_service_instance.service_subscription.cloud_regions), + tenant=tenant or next(aai_service_instance.service_subscription.tenants), + project=project, + owning_entity=owning_entity, + line_of_business=line_of_business, + platform=platform, + service_instance=aai_service_instance, + pnf_parameters=pnf_parameters or [], + so_pnf=so_pnf + ), + headers=headers_so_creator(OnapService.headers) + ) + + return PnfInstantiation( + name=pnf_instance_name, + request_id=response["requestReferences"]["requestId"], + instance_id=response["requestReferences"]["instanceId"], + line_of_business=line_of_business, + platform=platform, + pnf=pnf_object + ) class ServiceInstantiation(Instantiation): # pylint: disable=too-many-ancestors """Service instantiation class.""" diff --git a/src/onapsdk/so/templates/instantiate_pnf_macro.json.j2 b/src/onapsdk/so/templates/instantiate_pnf_macro.json.j2 new file mode 100755 index 0000000..6abfe84 --- /dev/null +++ b/src/onapsdk/so/templates/instantiate_pnf_macro.json.j2 @@ -0,0 +1,121 @@ +{
+ "requestDetails": {
+ "requestInfo": {
+ "instanceName": "{{ service_instance.instance_name }}",
+ "source": "VID",
+ "suppressRollback": false,
+ "requestorId": "demo",
+ "productFamilyId": "1234"
+ },
+ "modelInfo": {
+ "modelType": "pnf",
+ "modelInvariantId": "{{ pnf.model_invariant_id }}",
+ "modelVersionId": "{{ pnf.model_version_id }}",
+ "modelName": "{{ pnf.model_name }}",
+ "modelVersion": "{{ pnf.model_version }}",
+ "modelCustomizationId": "{{ pnf.model_customization_id }}",
+ "modelInstanceName": "{{ pnf.name }}"
+ },
+ "cloudConfiguration": {
+ "tenantId": "{{ tenant.tenant_id }}",
+ "cloudOwner": "{{ cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ cloud_region.cloud_region_id }}"
+ },
+ "platform": {
+ "platformName": "{{ platform }}"
+ },
+ "lineOfBusiness": {
+ "lineOfBusinessName": "{{ line_of_business }}"
+ },
+ "subscriberInfo": {
+ "globalSubscriberId": "{{ service_instance.service_subscription.customer.global_customer_id }}"
+ },
+ "requestParameters": {
+ {% block subscriptionServiceType %}
+ "subscriptionServiceType": "{{ service.name }}",
+ {% endblock %}
+ "userParams": [
+ {
+ "Homing_Solution": "none"
+ },
+ {
+ "service": {
+ "instanceParams": [],
+ "resources": {
+ {% block pnfs %}
+ "pnfs": [
+ {
+ "modelInfo": {
+ "modelName": "{{ pnf.model_name }}",
+ "modelVersionId": "{{ pnf.model_version_id }}",
+ "modelInvariantUuid": "{{ pnf.model_invariant_id }}",
+ "modelVersion": "{{ pnf.model_version }}",
+ "modelCustomizationId": "{{ pnf.model_customization_id }}",
+ "modelInstanceName": "{{ pnf.name }}"
+ },
+ "cloudConfiguration": {
+ "tenantId": "{{ tenant.tenant_id }}",
+ "cloudOwner": "{{ cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ cloud_region.cloud_region_id }}"
+ },
+ "platform": {
+ "platformName": "{{ platform }}"
+ },
+ "lineOfBusiness": {
+ "lineOfBusinessName": "{{ line_of_business }}"
+ },
+ "productFamilyId": "1234",
+ "instanceName": "{{ instance_name }}",
+ "instanceParams": [
+ {
+ {% for pnf_parameter in pnf_parameters %}
+ {% if pnf_parameter.name == pnf.model_name %}
+ {% for parameter in pnf_parameter.pnf_parameters %}
+ "{{ parameter.name }}": "{{ parameter.value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+ }
+ ],
+ }
+ ]
+ {% endblock %}
+ },
+ "modelInfo": {
+ "modelType": "pnf",
+ "modelInvariantId": "{{ pnf.model_invariant_id }}",
+ "modelVersionId": "{{ pnf.model_version_id }}",
+ "modelName": "{{ pnf.model_name }}",
+ "modelVersion": "{{ pnf.model_version }}",
+ "modelCustomizationId": "{{ pnf.model_customization_id }}",
+ "modelCustomizationName": "{{ pnf.name }}"
+ }
+ }
+ }
+ ],
+ "aLaCarte": false
+ },
+ "project": {
+ "projectName": "{{ project }}"
+ },
+ "owningEntity": {
+ "owningEntityId": "{{ owning_entity.owning_entity_id }}",
+ "owningEntityName": "{{ owning_entity.name }}"
+ },
+ "relatedInstanceList": [
+ {
+ "relatedInstance": {
+ "instanceId": "{{ service_instance.instance_id }}",
+ "modelInfo": {
+ "modelType": "service",
+ "modelInvariantId": "{{ service.unique_uuid }}",
+ "modelVersionId": "{{ service.identifier }}",
+ "modelName": "{{ service.name }}",
+ "modelVersion": "1.0"
+ }
+ }
+ }
+ ]
+ },
+ "serviceInstanceId": "{{ service_instance.instance_id }}"
+}
diff --git a/src/onapsdk/so/templates/instantiate_pnf_macro_so_pnf.json.j2 b/src/onapsdk/so/templates/instantiate_pnf_macro_so_pnf.json.j2 new file mode 100755 index 0000000..a6571bd --- /dev/null +++ b/src/onapsdk/so/templates/instantiate_pnf_macro_so_pnf.json.j2 @@ -0,0 +1,117 @@ +{
+ "requestDetails": {
+ "requestInfo": {
+ "instanceName": "{{ service_instance.instance_name }}",
+ "source": "VID",
+ "suppressRollback": false,
+ "requestorId": "demo",
+ "productFamilyId": "1234"
+ },
+ "modelInfo": {
+ "modelType": "pnf",
+ "modelInvariantId": "{{ pnf.model_invariant_id }}",
+ "modelVersionId": "{{ pnf.model_version_id }}",
+ "modelName": "{{ pnf.model_name }}",
+ "modelVersion": "{{ pnf.model_version }}",
+ "modelCustomizationId": "{{ pnf.model_customization_id }}",
+ "modelInstanceName": "{{ pnf.name }}"
+ },
+ "cloudConfiguration": {
+ "tenantId": "{{ tenant.tenant_id }}",
+ "cloudOwner": "{{ cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ cloud_region.cloud_region_id }}"
+ },
+ "platform": {
+ "platformName": "{{ platform }}"
+ },
+ "lineOfBusiness": {
+ "lineOfBusinessName": "{{ line_of_business }}"
+ },
+ "subscriberInfo": {
+ "globalSubscriberId": "{{ service_instance.service_subscription.customer.global_customer_id }}"
+ },
+ "requestParameters": {
+ {% block subscriptionServiceType %}
+ "subscriptionServiceType": "{{ service.name }}",
+ {% endblock %}
+ "userParams": [
+ {
+ "Homing_Solution": "none"
+ },
+ {
+ "service": {
+ "instanceParams": [],
+ "resources": {
+ {% block pnfs %}
+ "pnfs": [
+ {
+ "modelInfo": {
+ "modelName": "{{ pnf.model_name }}",
+ "modelVersionId": "{{ pnf.model_version_id }}",
+ "modelInvariantUuid": "{{ pnf.model_invariant_id }}",
+ "modelVersion": "{{ pnf.model_version }}",
+ "modelCustomizationId": "{{ pnf.model_customization_id }}",
+ "modelInstanceName": "{{ pnf.name }}"
+ },
+ "cloudConfiguration": {
+ "tenantId": "{{ tenant.tenant_id }}",
+ "cloudOwner": "{{ cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ cloud_region.cloud_region_id }}"
+ },
+ "platform": {
+ "platformName": "{{ platform }}"
+ },
+ "lineOfBusiness": {
+ "lineOfBusinessName": "{{ line_of_business }}"
+ },
+ "productFamilyId": "1234",
+ "instanceName": "{{ instance_name }}",
+ "instanceParams": [
+ {
+ {% for key, value in so_pnf.parameters.items() %}
+ "{{ key }}": "{{ value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ }
+ ],
+ }
+ ]
+ {% endblock %}
+ },
+ "modelInfo": {
+ "modelType": "pnf",
+ "modelInvariantId": "{{ pnf.model_invariant_id }}",
+ "modelVersionId": "{{ pnf.model_version_id }}",
+ "modelName": "{{ pnf.model_name }}",
+ "modelVersion": "{{ pnf.model_version }}",
+ "modelCustomizationId": "{{ pnf.model_customization_id }}",
+ "modelCustomizationName": "{{ pnf.name }}"
+ }
+ }
+ }
+ ],
+ "aLaCarte": false
+ },
+ "project": {
+ "projectName": "{{ project }}"
+ },
+ "owningEntity": {
+ "owningEntityId": "{{ owning_entity.owning_entity_id }}",
+ "owningEntityName": "{{ owning_entity.name }}"
+ },
+ "relatedInstanceList": [
+ {
+ "relatedInstance": {
+ "instanceId": "{{ service_instance.instance_id }}",
+ "modelInfo": {
+ "modelType": "service",
+ "modelInvariantId": "{{ service.unique_uuid }}",
+ "modelVersionId": "{{ service.identifier }}",
+ "modelName": "{{ service.name }}",
+ "modelVersion": "1.0"
+ }
+ }
+ }
+ ]
+ },
+ "serviceInstanceId": "{{ service_instance.instance_id }}"
+}
diff --git a/tests/test_so_instantiation.py b/tests/test_so_instantiation.py index ec796a9..1374b84 100644 --- a/tests/test_so_instantiation.py +++ b/tests/test_so_instantiation.py @@ -31,6 +31,7 @@ from onapsdk.so.instantiation import ( SoServiceVnf, VfModuleInstantiation, VnfInstantiation, + PnfInstantiation, ServiceOperation, VnfOperation ) @@ -344,6 +345,71 @@ def test_vnf_instantiation_macro(mock_owning_entity_get, mock_vnf_instantiation_ so_vnf=so_vnf_mock) assert vnf_instantiation.name == "SoVnfInstanceName" +@mock.patch.object(PnfInstantiation, "send_message_json") +@mock.patch.object(OwningEntity, "get_by_owning_entity_id") +def test_pnf_instantiation_macro(mock_owning_entity_get, mock_pnf_instantiation_send_message): + aai_service_instance_mock = mock.MagicMock() + aai_service_instance_mock.instance_id = "test_instance_id" + + relation_1 = mock.MagicMock() + relation_1.related_to = "owning-entity" + relation_1.relationship_data = [{"relationship-value": "test"}] + relation_2 = mock.MagicMock() + relation_2.related_to = "project" + relation_2.relationship_data = [{"relationship-value": "test"}] + + aai_service_instance_mock.relationships = (item for item in [relation_1, relation_2]) + + pnf_instantiation = PnfInstantiation.\ + instantiate_macro(aai_service_instance=aai_service_instance_mock, + pnf_object=mock.MagicMock(), + line_of_business="test_lob", + platform="test_platform", + cloud_region=mock.MagicMock(), + tenant=mock.MagicMock(), + sdc_service=mock.MagicMock()) + assert pnf_instantiation.name.startswith("Python_ONAP_SDK_pnf_instance_") + mock_pnf_instantiation_send_message.assert_called_once() + method, _, url = mock_pnf_instantiation_send_message.call_args[0] + assert method == "POST" + assert url == (f"{PnfInstantiation.base_url}/onap/so/infra/serviceInstantiation/" + f"{PnfInstantiation.api_version}/serviceInstances/" + f"{aai_service_instance_mock.instance_id}/pnfs") + + pnf_instantiation = PnfInstantiation. \ + instantiate_macro(aai_service_instance=aai_service_instance_mock, + pnf_object=mock.MagicMock(), + line_of_business="test_lob", + platform="test_platform", + pnf_instance_name="test", + cloud_region=mock.MagicMock(), + tenant=mock.MagicMock(), + sdc_service=mock.MagicMock()) + assert pnf_instantiation.name == "test" + + pnf_instantiation = PnfInstantiation. \ + instantiate_macro(aai_service_instance=aai_service_instance_mock, + pnf_object=mock.MagicMock(), + line_of_business="test_lob", + platform="test_platform", + cloud_region=mock.MagicMock(), + tenant=mock.MagicMock(), + sdc_service=mock.MagicMock(), + so_pnf=mock.MagicMock()) + assert pnf_instantiation.name.startswith("Python_ONAP_SDK_service_instance_") + + so_pnf_mock = mock.MagicMock() + so_pnf_mock.instance_name = "SoPnfInstanceName" + pnf_instantiation = PnfInstantiation. \ + instantiate_macro(aai_service_instance=aai_service_instance_mock, + pnf_object=mock.MagicMock(), + line_of_business="test_lob", + platform="test_platform", + cloud_region=mock.MagicMock(), + tenant=mock.MagicMock(), + sdc_service=mock.MagicMock(), + so_pnf=so_pnf_mock) + assert pnf_instantiation.name == "SoPnfInstanceName" @mock.patch.object(VnfInstantiation, "send_message_json") @mock.patch.object(OwningEntity, "get_by_owning_entity_id") @@ -626,6 +692,114 @@ def test_vnf_instantiation_get_by_vnf_instance_name(mock_sdc_service, mock_send_ } assert VnfInstantiation.get_by_vnf_instance_name("test_vnf_instance_name") is not None +@mock.patch.object(Vid, "send_message") +@mock.patch.object(PnfInstantiation, "send_message_json") +@mock.patch("onapsdk.so.instantiation.SdcService") +def test_pnf_instantiation_get_by_pnf_instance_name(mock_sdc_service, mock_send_message_json, mock_send): + mock_sdc_service.return_value.pnfs = [] + mock_send_message_json.return_value = {} + with pytest.raises(InvalidResponse): + PnfInstantiation.get_by_pnf_instance_name("test_pnf_instance_name") + mock_send_message_json.return_value = { + "requestList": [ + ] + } + with pytest.raises(InvalidResponse): + PnfInstantiation.get_by_pnf_instance_name("test_pnf_instance_name") + mock_send_message_json.return_value = { + "requestList1": [ + ] + } + with pytest.raises(InvalidResponse): + PnfInstantiation.get_by_pnf_instance_name("test_pnf_instance_name") + mock_send_message_json.return_value = { + "requestList": [ + { + "request": { + "requestScope": "not_pnf" + } + } + ] + } + with pytest.raises(InvalidResponse): + PnfInstantiation.get_by_pnf_instance_name("test_pnf_instance_name") + mock_send_message_json.return_value = { + "requestList": [ + { + "request": { + "requestScope": "pnf", + "requestType": "updateInstance" + } + } + ] + } + with pytest.raises(InvalidResponse): + PnfInstantiation.get_by_pnf_instance_name("test_pnf_instance_name") + mock_send_message_json.return_value = { + "requestList": [ + { + "request": { + "requestScope": "pnf", + "requestType": "createInstance" + } + } + ] + } + with pytest.raises(ResourceNotFound): + PnfInstantiation.get_by_pnf_instance_name("test_pnf_instance_name") + mock_send_message_json.return_value = { + "requestList": [ + { + "request": { + "requestScope": "pnf", + "requestType": "createInstance", + "requestDetails": { + "relatedInstanceList": [ + { + "relatedInstance": { + "modelInfo": { + "modelType": "service", + "modelName": "test_service" + } + } + } + ] + } + } + } + ] + } + with pytest.raises(ResourceNotFound): + PnfInstantiation.get_by_pnf_instance_name("test_pnf_instance_name") + mock_pnf = mock.MagicMock() + mock_pnf.name = "test_pnf_name" + mock_sdc_service.return_value.pnfs = [mock_pnf] + mock_send_message_json.return_value = { + "requestList": [ + { + "request": { + "requestScope": "pnf", + "requestType": "createInstance", + "requestDetails": { + "modelInfo": { + "modelCustomizationName": "test_pnf_name" + }, + "relatedInstanceList": [ + { + "relatedInstance": { + "modelInfo": { + "modelType": "service", + "modelName": "test_service" + } + } + } + ] + } + } + } + ] + } + assert PnfInstantiation.get_by_pnf_instance_name("test_pnf_instance_name") is not None @mock.patch.object(VfModuleInstantiation, "send_message_json") @mock.patch.object(VfModulePreload, "upload_vf_module_preload") |