From 88b7bcd9aafd7f60acde56259fdb419af100ac78 Mon Sep 17 00:00:00 2001 From: sanket12345 Date: Mon, 9 Jan 2023 05:09:04 +0000 Subject: API support for Upgrade Scenarios -API Support in Automation- ONAPSDK for -Service Upgrade -CNF Upgrade Issue-ID: INT-2187 Change-Id: I09f42f825b818b770f02f1d801bcd0084b8b8bab Signed-off-by: sanket12345 --- src/onapsdk/aai/business/vnf.py | 10 +++ src/onapsdk/so/instantiation.py | 90 ++++++++++++++++++++++-- src/onapsdk/so/templates/upgrade_service.json.j2 | 38 ++++++++++ tests/test_aai_vnf.py | 13 ++++ tests/test_so_instantiation.py | 72 ++++++++++++++++++- 5 files changed, 216 insertions(+), 7 deletions(-) create mode 100644 src/onapsdk/so/templates/upgrade_service.json.j2 diff --git a/src/onapsdk/aai/business/vnf.py b/src/onapsdk/aai/business/vnf.py index 2045291..39b1be0 100644 --- a/src/onapsdk/aai/business/vnf.py +++ b/src/onapsdk/aai/business/vnf.py @@ -428,6 +428,15 @@ class VnfInstance(Instance): # pylint: disable=too-many-instance-attributes """ return self._execute_so_action(operation_type=VnfOperation.HEALTHCHECK) + def upgrade(self) -> VnfInstantiation: + """Execute upgrade operation for vnf instance. + + Returns: + VnfInstantiation: VnfInstantiation object. + + """ + return self._execute_so_action(operation_type=VnfOperation.UPGRADE) + def _execute_so_action(self, operation_type: VnfOperation, vnf_parameters: Iterable["InstantiationParameter"] = None @@ -460,6 +469,7 @@ class VnfInstance(Instance): # pylint: disable=too-many-instance-attributes return VnfInstantiation.so_action( vnf_instance=self, + vnf_object=self._vnf, operation_type=operation_type, aai_service_instance=self.service_instance, line_of_business=lob, diff --git a/src/onapsdk/so/instantiation.py b/src/onapsdk/so/instantiation.py index bb0bde2..c1bf10e 100644 --- a/src/onapsdk/so/instantiation.py +++ b/src/onapsdk/so/instantiation.py @@ -1,4 +1,4 @@ -"""Instantion module.""" +"""Instantiation module.""" # Copyright 2022 Orange, Deutsche Telekom AG # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,7 +33,7 @@ from .so_element import OrchestrationRequest @dataclass -class Operation: +class Operation: # pylint: disable=too-many-lines """Operation class with data about method and suffix for VnfOperation.""" request_method: str @@ -45,6 +45,13 @@ class VnfOperation(Operation): # pylint: disable=too-few-public-methods UPDATE = Operation("PUT", "") HEALTHCHECK = Operation("POST", "/healthcheck") + UPGRADE = Operation("POST", "/upgradeCnf") + + +class ServiceOperation(Operation): # pylint: disable=too-few-public-methods + """Class to store possible operations' data for service (request method and suffix).""" + + UPGRADE_SERVICE = Operation("POST", "/upgrade") @dataclass @@ -571,6 +578,7 @@ class VnfInstantiation(NodeTemplateInstantiation): # pylint: disable=too-many-a @classmethod def so_action(cls, # pylint: disable=too-many-arguments, too-many-locals vnf_instance: "VnfInstance", + vnf_object: "Vnf", operation_type: VnfOperation, aai_service_instance: "ServiceInstance", line_of_business: str, @@ -582,6 +590,7 @@ class VnfInstantiation(NodeTemplateInstantiation): # pylint: disable=too-many-a Args: vnf_instance (VnfInstance): vnf instance object + vnf_object(VnfObject): vnf object operation_type (VnfOperation): name of the operation to trigger aai_service_instance (AaiService): Service Instance object from aai line_of_business (LineOfBusiness): LineOfBusiness name to use @@ -597,7 +606,9 @@ class VnfInstantiation(NodeTemplateInstantiation): # pylint: disable=too-many-a VnfInstantiation: VnfInstantiation object """ - if operation_type not in (VnfOperation.HEALTHCHECK, VnfOperation.UPDATE): + if operation_type not in (VnfOperation.HEALTHCHECK, + VnfOperation.UPDATE, + VnfOperation.UPGRADE): raise StatusError("Operation not supported!") owning_entity_id = None @@ -628,8 +639,11 @@ class VnfInstantiation(NodeTemplateInstantiation): # pylint: disable=too-many-a owning_entity=owning_entity, line_of_business=line_of_business, platform=platform, - service_instance_name=aai_service_instance.instance_name, - so_service=so_service + service_instance_name=so_service.instance_name, + so_service=so_service, + service_instance=aai_service_instance, + vnf=vnf_object, + service=so_service ), headers=headers_so_creator(OnapService.headers) ) @@ -845,6 +859,72 @@ class ServiceInstantiation(Instantiation): # pylint: disable=too-many-ancestors project=project ) + @classmethod + def so_service_action(cls, # pylint: disable=too-many-arguments, too-many-locals + aai_service_instance: "ServiceInstance", + operation_svc_type: ServiceOperation, + platform: str, + sdc_service: "SdcService", + so_service: "SoService" = None + ) -> "ServiceInstantiation": + """Select Service with SO macro request. + + Raises: + StatusError: if the provided operation is not supported + + Returns: + ServiceInstantiation: ServiceInstantiation object + + """ + if operation_svc_type == ServiceOperation.UPGRADE_SERVICE: + template = "upgrade_service.json.j2" + else: + raise StatusError("Operation not supported!") + + 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) + + response: dict = cls.send_message_json( + operation_svc_type.request_method, + (f"So Action {sdc_service.name} " + f" Service instance {aai_service_instance.instance_id}"), + (f"{cls.base_url}/onap/so/infra/serviceInstantiation/{cls.api_version}/" + f"serviceInstances/{aai_service_instance.instance_id}" + f"{operation_svc_type.request_suffix}"), + data=jinja_env().get_template(template).render( + sdc_service=sdc_service, + cloud_region=next(aai_service_instance.service_subscription.cloud_regions), + tenant=next(aai_service_instance.service_subscription.tenants), + project=project, + owning_entity=owning_entity, + platform=platform, + service_instance=aai_service_instance, + service=so_service + ), + headers=headers_so_creator(OnapService.headers) + ) + + return ServiceInstantiation( + request_id=response["requestReferences"]["requestId"], + instance_id=response["requestReferences"]["instanceId"], + name=aai_service_instance.name, + sdc_service="SdcService", + cloud_region="CloudRegion", + tenant="Tenant", + customer="Customer", + owning_entity=OwningEntity, + project=project + ) + @property def aai_service_instance(self) -> "ServiceInstance": """Service instance associated with service instantiation request. diff --git a/src/onapsdk/so/templates/upgrade_service.json.j2 b/src/onapsdk/so/templates/upgrade_service.json.j2 new file mode 100644 index 0000000..b2e1c95 --- /dev/null +++ b/src/onapsdk/so/templates/upgrade_service.json.j2 @@ -0,0 +1,38 @@ +{ + "requestDetails": { + "subscriberInfo": { + "globalSubscriberId": "{{ service_instance.service_subscription.customer.global_customer_id }}" + }, + "requestInfo": { + "suppressRollback": "false", + "productFamilyId": "1234", + "requestorId": "demo", + "instanceName": "{{ service_instance.instance_name }}", + "source": "VID" + }, + "cloudConfiguration": { + "tenantId": "{{ service_instance.service_subscription.tenant.tenant_id }}", + "cloudOwner": "{{ service_instance.service_subscription.cloud_region.cloud_owner }}", + "lcpCloudRegionId": "{{ service_instance.service_subscription.cloud_region.cloud_region_id }}" + }, + "requestParameters": { + "subscriptionServiceType": "{{ service.name }}", + "userParams": [], + "aLaCarte": "false" + }, + "project": { + "projectName": "{{ project }}" + }, + "owningEntity": { + "owningEntityId": "{{ owning_entity.owning_entity_id }}", + "owningEntityName": "{{ owning_entity.name }}" + }, + "modelInfo": { + "modelVersion": "{{ service_instance.sdc_service.version }}", + "modelVersionId": "{{ service_instance.sdc_service.identifier }}", + "modelInvariantId": "{{ service_instance.sdc_service.unique_uuid }}", + "modelName": "{{ service_instance.sdc_service.name }}", + "modelType": "service" + } + } + } \ No newline at end of file diff --git a/tests/test_aai_vnf.py b/tests/test_aai_vnf.py index 4dea6a8..ae82d4c 100644 --- a/tests/test_aai_vnf.py +++ b/tests/test_aai_vnf.py @@ -325,6 +325,19 @@ def test_vnf_healthcheck(mock_vnf_instantiation): vnf_instance.healthcheck() mock_vnf_instantiation.assert_called_once() +@mock.patch.object(VnfInstance, "_execute_so_action") +def test_vnf_upgrade(mock_vnf_instantiation): + + instance3 = mock.MagicMock() + vnf_instance3 = VnfInstance(instance3, + vnf_id="test_vnf_id", + vnf_type="test_vnf_type", + in_maint=False, + is_closed_loop_disabled=True) + + vnf_instance3.upgrade() + mock_vnf_instantiation.assert_called_once() + @mock.patch.object(VnfInstance, "_build_so_input") @mock.patch.object(VnfInstantiation, "so_action") diff --git a/tests/test_so_instantiation.py b/tests/test_so_instantiation.py index 5c8f41a..ec796a9 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, + ServiceOperation, VnfOperation ) from onapsdk.vid import Vid @@ -145,6 +146,48 @@ def test_service_macro_instantiation(mock_service_instantiation_send_message): assert url == (f"{ServiceInstantiation.base_url}/onap/so/infra/" f"serviceInstantiation/{ServiceInstantiation.api_version}/serviceInstances") +##upgrade service +@mock.patch.object(ServiceInstantiation, "send_message_json") +@mock.patch.object(OwningEntity, "get_by_owning_entity_id") +def test_svc_macro_so_action(mock_owning_entity_get, mock_svc_instantiation_send_message): + + mock_sdc_service = mock.MagicMock() + mock_aai_service_instance = mock.MagicMock() + mock_aai_service_instance.instance_id = mock.MagicMock() + mock_aai_service_instance.service_subscription = mock.MagicMock() + with pytest.raises(StatusError): + ServiceInstantiation. \ + so_service_action(operation_svc_type=mock.MagicMock(), + aai_service_instance=mock_aai_service_instance, + platform=mock.MagicMock(), + sdc_service=mock_sdc_service, + so_service=mock.MagicMock()) + 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"}] + + mock_aai_service_instance = mock.MagicMock() + mock_aai_service_instance.instance_id = mock.MagicMock() + mock_aai_service_instance.service_subscription = mock.MagicMock() + mock_aai_service_instance.relationships = (item for item in [relation_1, relation_2]) + + ##upgradeAPI of Service + svc_instance_upgrade = ServiceInstantiation. \ + so_service_action(operation_svc_type=ServiceOperation.UPGRADE_SERVICE, + aai_service_instance=mock_aai_service_instance, + platform=mock.MagicMock(), + sdc_service=mock_sdc_service, + so_service=mock.MagicMock()) + assert svc_instance_upgrade.name.startswith("Python_ONAP_SDK_service_instance_") + mock_svc_instantiation_send_message.assert_called() + method, _, url = mock_svc_instantiation_send_message.call_args[0] + assert method == "POST" + assert url == (f"{ServiceInstantiation.base_url}/onap/so/infra/" + f"serviceInstantiation/{ServiceInstantiation.api_version}/serviceInstances/" + f"{mock_aai_service_instance.instance_id}/upgrade") def test_service_instance_aai_service_instance(): customer_mock = mock.MagicMock() @@ -310,6 +353,7 @@ def test_vnf_macro_so_action(mock_owning_entity_get, mock_vnf_instantiation_send with pytest.raises(StatusError): VnfInstantiation.\ so_action(vnf_instance=mock.MagicMock(), + vnf_object=mock.MagicMock(), operation_type=mock.MagicMock(), aai_service_instance=mock.MagicMock(), line_of_business=mock.MagicMock(), @@ -339,7 +383,8 @@ def test_vnf_macro_so_action(mock_owning_entity_get, mock_vnf_instantiation_send line_of_business=mock.MagicMock(), platform=mock.MagicMock(), sdc_service=mock_sdc_service, - so_service=mock.MagicMock()) + so_service=mock.MagicMock(), + vnf_object=mock.MagicMock()) assert vnf_instance_update.name == "test_name_update" mock_vnf_instantiation_send_message.assert_called() method, _, url = mock_vnf_instantiation_send_message.call_args[0] @@ -358,7 +403,8 @@ def test_vnf_macro_so_action(mock_owning_entity_get, mock_vnf_instantiation_send line_of_business=mock.MagicMock(), platform=mock.MagicMock(), sdc_service=mock_sdc_service, - so_service=mock.MagicMock()) + so_service=mock.MagicMock(), + vnf_object=mock.MagicMock()) assert vnf_instance_healthcheck.name == "test_name_healthcheck" mock_vnf_instantiation_send_message.assert_called() method, _, url = mock_vnf_instantiation_send_message.call_args[0] @@ -368,6 +414,28 @@ def test_vnf_macro_so_action(mock_owning_entity_get, mock_vnf_instantiation_send f"{mock_aai_service_instance.instance_id}/vnfs/{mock_vnf_instance.vnf_id}/healthcheck") + ##upgradeAPI of cnf + mock_vnf_instance = mock.MagicMock() + mock_vnf_instance.vnf_name = "test_name_upgrade" + vnf_instance_upgrade = VnfInstantiation. \ + so_action(vnf_instance=mock_vnf_instance, + operation_type=VnfOperation.UPGRADE, + aai_service_instance=mock_aai_service_instance, + line_of_business=mock.MagicMock(), + platform=mock.MagicMock(), + sdc_service=mock_sdc_service, + so_service=mock.MagicMock(), + vnf_object=mock.MagicMock()) + assert vnf_instance_upgrade.name == "test_name_upgrade" + mock_vnf_instantiation_send_message.assert_called() + method, _, url = mock_vnf_instantiation_send_message.call_args[0] + assert method == "POST" + assert url == (f"{ServiceInstantiation.base_url}/onap/so/infra/" + f"serviceInstantiation/{ServiceInstantiation.api_version}/serviceInstances/" + f"{mock_aai_service_instance.instance_id}/vnfs/{mock_vnf_instance.vnf_id}/upgradeCnf") + + + @mock.patch.object(NetworkInstantiation, "send_message_json") @mock.patch.object(NetworkPreload, "send_message_json") def test_network_instantiation(mock_network_preload, mock_network_instantiation_send_message): -- cgit 1.2.3-korg