aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/onapsdk/aai/business/pnf.py18
-rw-r--r--src/onapsdk/so/deletion.py31
-rw-r--r--src/onapsdk/so/instantiation.py28
-rw-r--r--src/onapsdk/so/templates/deletion_pnf.json.j227
-rwxr-xr-xsrc/onapsdk/so/templates/instantiate_pnf_macro_so_pnf.json.j213
-rw-r--r--src/onapsdk/so/templates/instantiate_service_macro.json.j210
-rw-r--r--tests/test_aai_pnf.py31
-rw-r--r--[-rwxr-xr-x]tests/test_service.py0
-rw-r--r--tests/test_so_deletion.py19
-rw-r--r--tests/test_so_instantiation.py64
10 files changed, 223 insertions, 18 deletions
diff --git a/src/onapsdk/aai/business/pnf.py b/src/onapsdk/aai/business/pnf.py
index 9061ebf..9f5394f 100644
--- a/src/onapsdk/aai/business/pnf.py
+++ b/src/onapsdk/aai/business/pnf.py
@@ -16,6 +16,7 @@
from typing import Iterator, Optional, TYPE_CHECKING
from onapsdk.exceptions import ResourceNotFound
+from onapsdk.so.deletion import PnfDeletionRequest
from .instance import Instance
if TYPE_CHECKING:
@@ -254,14 +255,17 @@ class PnfInstance(Instance): # pylint: disable=too-many-instance-attributes
pnf_ipv4_address=api_response.get("pnf-ipv4-address"),
pnf_ipv6_address=api_response.get("pnf-ipv6-address"))
- def delete(self, a_la_carte: bool = True) -> None:
- """Delete Pnf instance.
+ def delete(self, a_la_carte: bool = True) -> "PnfDeletionRequest":
+ """Create PNF deletion request.
- PNF deletion it's just A&AI resource deletion. That's difference between another instances.
- You don't have to wait for that task finish, because it's not async task.
+ Send request to delete PNF instance
+
+ Args:
+ a_la_carte (boolean): deletion mode
+
+ Returns:
+ PnfDeletionRequest: Deletion request
"""
self._logger.debug("Delete %s pnf", self.pnf_name)
- self.send_message("DELETE",
- f"Delete {self.pnf_name} PNF",
- f"{self.url}?resource-version={self.resource_version}")
+ return PnfDeletionRequest.send_request(self, a_la_carte)
diff --git a/src/onapsdk/so/deletion.py b/src/onapsdk/so/deletion.py
index 35ff0ee..5b299f8 100644
--- a/src/onapsdk/so/deletion.py
+++ b/src/onapsdk/so/deletion.py
@@ -102,6 +102,37 @@ class VnfDeletionRequest(DeletionRequest): # pytest: disable=too-many-ancestors
headers=headers_so_creator(OnapService.headers))
return cls(request_id=response["requestReferences"]["requestId"])
+class PnfDeletionRequest(DeletionRequest): # pytest: disable=too-many-ancestors
+ """PNF deletion class."""
+
+ @classmethod
+ def send_request(cls,
+ instance: "PnfInstance",
+ a_la_carte: bool = True) -> "PnfDeletionRequest":
+ """Send request to SO to delete PNF instance.
+
+ Args:
+ instance (PnfInstance): PNF instance to delete
+ a_la_carte (boolean): deletion mode
+
+ Returns:
+ PnfDeletionRequest: Deletion request object
+
+ """
+ cls._logger.debug("PNF %s deletion request", instance.pnf_id)
+ response = cls.send_message_json("DELETE",
+ f"Create {instance.pnf_id} PNF deletion request",
+ (f"{cls.base_url}/onap/so/infra/"
+ f"serviceInstantiation/{cls.api_version}/"
+ "serviceInstances/"
+ f"{instance.service_instance.instance_id}/"
+ f"pnfs/{instance.pnf_id}"),
+ data=jinja_env().
+ get_template("deletion_pnf.json.j2").
+ render(pnf_instance=instance,
+ a_la_carte=a_la_carte),
+ headers=headers_so_creator(OnapService.headers))
+ return cls(request_id=response["requestReferences"]["requestId"])
class ServiceDeletionRequest(DeletionRequest): # pytest: disable=too-many-ancestors
"""Service deletion request class."""
diff --git a/src/onapsdk/so/instantiation.py b/src/onapsdk/so/instantiation.py
index 8130b00..a6781de 100644
--- a/src/onapsdk/so/instantiation.py
+++ b/src/onapsdk/so/instantiation.py
@@ -97,6 +97,7 @@ class SoServiceVnf(SoServiceXnf):
class SoServicePnf(SoServiceXnf):
"""Class to store a Pnf instance parameters."""
+ registration_parameters: Optional["PnfRegistrationParameters"] = None
@dataclass
class SoService:
@@ -109,6 +110,7 @@ class SoService:
subscription_service_type: str
vnfs: List[SoServiceVnf] = field(default_factory=list)
pnfs: List[SoServicePnf] = field(default_factory=list)
+ parameters: Dict[str, Any] = field(default_factory=dict)
instance_name: Optional[str] = None
@classmethod
@@ -149,6 +151,32 @@ class VfmoduleParameters:
@dataclass
+class PnfRegistrationParameters:
+ """Class to store parameters required for pnf-instantiation without pnf-registration-event.
+
+ Contains required parameters for instantiation request
+ """
+
+ model_number: str
+ oam_v4_ip_address: str
+ oam_v6_ip_address: str
+ serial_number: str
+ software_version: str
+ unit_type: str
+ vendor_name: str
+
+ @classmethod
+ def load(cls, data: Dict[str, Any]) -> "PnfRegistrationParameters":
+ """Create a PnfRegistrationParameters object from the dict.
+
+ Returns:
+ PnfRegistrationParameters: PnfRegistrationParameters object created from the dictionary
+
+ """
+ return from_dict(data_class=cls, data=data)
+
+
+@dataclass
class InstantiationParameter:
"""Class to store instantiation parameters used for preload or macro instantiation.
diff --git a/src/onapsdk/so/templates/deletion_pnf.json.j2 b/src/onapsdk/so/templates/deletion_pnf.json.j2
new file mode 100644
index 0000000..852432a
--- /dev/null
+++ b/src/onapsdk/so/templates/deletion_pnf.json.j2
@@ -0,0 +1,27 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "source": "VID",
+ "requestorId": "demo"
+ },
+ "modelInfo": {
+ "modelType": "pnf",
+ "modelName": "{{ pnf_instance.pnf.model_name }}",
+ "modelInvariantId": "{{ pnf_instance.pnf.model_invariant_id }}",
+ "modelVersion": "{{ pnf_instance.pnf.model_version }}",
+ "modelVersionId": "{{ pnf_instance.pnf.model_version_id }}",
+ "modelCustomizationId": "{{ pnf_instance.pnf.model_customization_id }}",
+ "modelCustomizationName": "{{ pnf_instance.pnf.name }}"
+ },
+ "requestParameters": {
+ "testApi": "GR_API",
+ "aLaCarte": {{ a_la_carte | tojson }}
+ },
+ {# the code below is needed to be refactored #
+ }
+ {# https: //gitlab.com/Orange-OpenSource/lfn/onap/python-onapsdk/-/issues/133 #} "cloudConfiguration": { "cloudOwner": "{{ pnf_instance.service_instance.service_subscription.cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ pnf_instance.service_instance.service_subscription.cloud_region.cloud_region_id }}",
+ "tenantId": "{{ pnf_instance.service_instance.service_subscription.tenant.tenant_id }}"
+ }
+ }
+} \ No newline at end of file
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
index a6571bd..5f1f22c 100755
--- a/src/onapsdk/so/templates/instantiate_pnf_macro_so_pnf.json.j2
+++ b/src/onapsdk/so/templates/instantiate_pnf_macro_so_pnf.json.j2
@@ -64,6 +64,17 @@
"lineOfBusiness": {
"lineOfBusinessName": "{{ line_of_business }}"
},
+ {% if so_pnf.registration_parameters %}
+ "pnfRegistrationFields": {
+ "modelNumber": "{{ so_pnf.registration_parameters.model_number }}",
+ "oamV4IpAddress": "{{ so_pnf.registration_parameters.oam_v4_ip_address }}",
+ "oamV6IpAddress": "{{ so_pnf.registration_parameters.oam_v6_ip_address }}",
+ "serialNumber": "{{ so_pnf.registration_parameters.serial_number }}",
+ "softwareVersion": "{{ so_pnf.registration_parameters.software_version }}",
+ "unitType": "{{ so_pnf.registration_parameters.unit_type }}",
+ "vendorName": "{{ so_pnf.registration_parameters.vendor_name }}"
+ },
+ {% endif %}
"productFamilyId": "1234",
"instanceName": "{{ instance_name }}",
"instanceParams": [
@@ -72,7 +83,7 @@
"{{ key }}": "{{ value }}"{% if not loop.last %},{% endif %}
{% endfor %}
}
- ],
+ ]
}
]
{% endblock %}
diff --git a/src/onapsdk/so/templates/instantiate_service_macro.json.j2 b/src/onapsdk/so/templates/instantiate_service_macro.json.j2
index 43b92ee..b00a043 100644
--- a/src/onapsdk/so/templates/instantiate_service_macro.json.j2
+++ b/src/onapsdk/so/templates/instantiate_service_macro.json.j2
@@ -44,7 +44,15 @@
{% endif %}
{
"service": {
- "instanceParams": [],
+ "instanceParams": [
+ {% if so_service %}
+ {
+ {% for key, value in so_service.parameters.items() %}
+ "{{ key }}": "{{ value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ }
+ {% endif %}
+ ],
"instanceName": "{{ service_instance_name }}",
"resources": {
{% block pnfs %}
diff --git a/tests/test_aai_pnf.py b/tests/test_aai_pnf.py
index eb2e851..9c417ba 100644
--- a/tests/test_aai_pnf.py
+++ b/tests/test_aai_pnf.py
@@ -15,9 +15,9 @@ from unittest import mock
import pytest
-from onapsdk.aai.business import PnfInstance, pnf
+from onapsdk.aai.business import PnfInstance, pnf, ServiceInstance
from onapsdk.exceptions import ResourceNotFound
-# from onapsdk.so.deletion import NetworkDeletionRequest
+from onapsdk.so.deletion import PnfDeletionRequest
PNF_INSTANCE = {
@@ -104,13 +104,26 @@ def test_create_pnf_instance_from_api_response():
assert pnf_instance.url.endswith(pnf_instance.pnf_name)
-@mock.patch.object(PnfInstance, "send_message")
-def test_delete_pnf_instance(mock_send_message):
- pnf = PnfInstance(mock.MagicMock, "test_pnf", False)
- pnf.delete()
- method, _, address = mock_send_message.call_args[0]
- assert method == "DELETE"
- assert address == f"{pnf.url}?resource-version={pnf.resource_version}"
+@mock.patch.object(PnfDeletionRequest, "send_request")
+def test_delete_pnf_instance(mock_pnf_deletion_request):
+ service_instance = ServiceInstance(None,
+ instance_id="test_service_instance_id")
+ pnf_instance = PnfInstance(service_instance,
+ pnf_id="test_pnf_id",
+ pnf_name="test_pnf_name",
+ serial_number="test_serial_number",
+ in_maint=False)
+
+ assert pnf_instance.service_instance == service_instance
+ assert pnf_instance.pnf_id == "test_pnf_id"
+ assert pnf_instance.in_maint is False
+ assert pnf_instance.serial_number == "test_serial_number"
+ assert pnf_instance._pnf is None
+ assert pnf_instance.url == (f"{pnf_instance.base_url}{pnf_instance.api_version}/network/"
+ f"pnfs/pnf/{pnf_instance.pnf_name}")
+ pnf_instance.delete()
+ mock_pnf_deletion_request.assert_called_once_with(pnf_instance, True)
+
def test_pnf_instance_pnf():
diff --git a/tests/test_service.py b/tests/test_service.py
index 3a11449..3a11449 100755..100644
--- a/tests/test_service.py
+++ b/tests/test_service.py
diff --git a/tests/test_so_deletion.py b/tests/test_so_deletion.py
index ff10474..cbcbce3 100644
--- a/tests/test_so_deletion.py
+++ b/tests/test_so_deletion.py
@@ -14,6 +14,7 @@
from unittest import mock
from onapsdk.so.deletion import (
+ PnfDeletionRequest,
ServiceDeletionRequest,
VfModuleDeletionRequest,
VnfDeletionRequest
@@ -72,3 +73,21 @@ def test_vnf_deletion_request(mock_send_message):
f"serviceInstantiation/{VnfDeletionRequest.api_version}/"
"serviceInstances/test_service_instance/"
"vnfs/test_vnf_id")
+
+@mock.patch.object(PnfDeletionRequest, "send_message")
+def test_pnf_deletion_request(mock_send_message):
+ mock_pnf_instance = mock.MagicMock()
+ mock_pnf_instance.pnf_id = "test_pnf_id"
+
+ mock_service_instance = mock.MagicMock()
+ mock_service_instance.instance_id = "test_service_instance"
+ mock_pnf_instance.service_instance = mock_service_instance
+ PnfDeletionRequest.send_request(instance=mock_pnf_instance)
+ mock_send_message.assert_called_once()
+ method, _, url = mock_send_message.call_args[0]
+ assert method == "DELETE"
+ assert url == (f"{PnfDeletionRequest.base_url}/onap/so/infra/"
+ f"serviceInstantiation/{PnfDeletionRequest.api_version}/"
+ "serviceInstances/test_service_instance/"
+ "pnfs/test_pnf_id")
+
diff --git a/tests/test_so_instantiation.py b/tests/test_so_instantiation.py
index 1374b84..8f2a93e 100644
--- a/tests/test_so_instantiation.py
+++ b/tests/test_so_instantiation.py
@@ -32,6 +32,7 @@ from onapsdk.so.instantiation import (
VfModuleInstantiation,
VnfInstantiation,
PnfInstantiation,
+ PnfRegistrationParameters,
ServiceOperation,
VnfOperation
)
@@ -946,6 +947,59 @@ def test_service_instantiation_multicloud(mock_send_message_json):
data = json.loads(kwargs["data"])
assert any(filter(lambda x: x == {"name": "orchestrator", "value": "multicloud"}, data["requestDetails"]["requestParameters"]["userParams"]))
+@mock.patch.object(PnfInstantiation, "send_message_json")
+@mock.patch.object(OwningEntity, "get_by_owning_entity_id")
+def test_pnf_instantiation_so_service(mock_owning_entity_get, mock_send_message_json):
+ 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])
+
+ so_pnf = SoServicePnf(
+ model_name="test_so_service_pnf_model_name_1",
+ instance_name="test_so_service_pnf_instance_name_1",
+ registration_parameters=PnfRegistrationParameters(
+ model_number="test_model_number",
+ oam_v4_ip_address="test_ip",
+ oam_v6_ip_address="test_mac",
+ serial_number="test_serial_number",
+ software_version="test_software_version",
+ unit_type="test_unit_type",
+ vendor_name="test_vendor"
+ )
+ )
+
+ _ = 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)
+
+ _, kwargs = mock_send_message_json.call_args
+ data = json.loads(kwargs["data"])
+
+ pnf_data = data["requestDetails"]["requestParameters"]["userParams"][1]["service"]["resources"]["pnfs"][0]
+
+ assert pnf_data["instanceName"] == "test_so_service_pnf_instance_name_1"
+
+ assert pnf_data["pnfRegistrationFields"]["modelNumber"] == "test_model_number"
+ assert pnf_data["pnfRegistrationFields"]["oamV4IpAddress"] == "test_ip"
+ assert pnf_data["pnfRegistrationFields"]["oamV6IpAddress"] == "test_mac"
+ assert pnf_data["pnfRegistrationFields"]["serialNumber"] == "test_serial_number"
+ assert pnf_data["pnfRegistrationFields"]["softwareVersion"] == "test_software_version"
+ assert pnf_data["pnfRegistrationFields"]["unitType"] == "test_unit_type"
+ assert pnf_data["pnfRegistrationFields"]["vendorName"] == "test_vendor"
@mock.patch.object(ServiceInstantiation, "send_message_json")
def test_service_instantiation_so_service(mock_send_message_json):
@@ -954,6 +1008,10 @@ def test_service_instantiation_so_service(mock_send_message_json):
so_service = SoService(
subscription_service_type="test_so_service",
+ parameters={
+ "service_param_1": "service_param_1_value",
+ "service_param_2": "service_param_2_value"
+ },
vnfs=[
SoServiceVnf(
model_name="test_so_service_vnf_model_name_1",
@@ -1014,11 +1072,17 @@ def test_service_instantiation_so_service(mock_send_message_json):
assert data["requestDetails"]["requestParameters"]["subscriptionServiceType"] == "test_so_service"
assert len(data["requestDetails"]["requestParameters"]["userParams"][1]["service"]["resources"]["vnfs"]) == 2
assert len(data["requestDetails"]["requestParameters"]["userParams"][1]["service"]["resources"]["pnfs"]) == 2
+
+ instance_params = data["requestDetails"]["requestParameters"]["userParams"][1]["service"]["instanceParams"]
vnf_1_data = data["requestDetails"]["requestParameters"]["userParams"][1]["service"]["resources"]["vnfs"][0]
vnf_2_data = data["requestDetails"]["requestParameters"]["userParams"][1]["service"]["resources"]["vnfs"][1]
pnf_1_data = data["requestDetails"]["requestParameters"]["userParams"][1]["service"]["resources"]["pnfs"][0]
pnf_2_data = data["requestDetails"]["requestParameters"]["userParams"][1]["service"]["resources"]["pnfs"][1]
+ assert len(instance_params[0]) == 2
+ assert instance_params[0]["service_param_1"] == "service_param_1_value"
+ assert instance_params[0]["service_param_2"] == "service_param_2_value"
+
assert vnf_1_data["instanceName"] == "test_so_service_vnf_instance_name_1"
assert len(vnf_1_data["instanceParams"][0]) == 2
assert vnf_1_data["instanceParams"][0]["param_1"] == "param_1_value"