aboutsummaryrefslogtreecommitdiffstats
path: root/src/onapsdk/so
diff options
context:
space:
mode:
authorMichal Jagiello <michal.jagiello@t-mobile.pl>2022-10-17 12:46:49 +0000
committerMichal Jagiello <michal.jagiello@t-mobile.pl>2022-10-17 14:05:09 +0000
commitf2adf542e878c96895210f97ebf1ebb763b2f465 (patch)
tree91fc0faeb3436e723d07aed1f38ce59a6e7cc7c5 /src/onapsdk/so
parent49071a0d0425ef67fa552dbf14c81e5a11cc49e7 (diff)
Release ONAP SDKv10.2
Issue-ID: INT-2150 Signed-off-by: Michal Jagiello <michal.jagiello@t-mobile.pl> Change-Id: I650047c599a5aae6de7c6b42d38e34aea88578e2
Diffstat (limited to 'src/onapsdk/so')
-rw-r--r--src/onapsdk/so/__init__.py14
-rw-r--r--src/onapsdk/so/deletion.py167
-rw-r--r--src/onapsdk/so/instantiation.py957
-rw-r--r--src/onapsdk/so/so_db_adapter.py94
-rw-r--r--src/onapsdk/so/so_element.py223
-rw-r--r--src/onapsdk/so/templates/add_cloud_site_with_identity_service.json.j222
-rw-r--r--src/onapsdk/so/templates/deletion_network.json.j222
-rw-r--r--src/onapsdk/so/templates/deletion_service.json.j226
-rw-r--r--src/onapsdk/so/templates/deletion_vf_module.json.j227
-rw-r--r--src/onapsdk/so/templates/deletion_vnf.json.j228
-rw-r--r--src/onapsdk/so/templates/instantiate_multi_vnf_service_macro.json.j2121
-rw-r--r--src/onapsdk/so/templates/instantiate_network_ala_carte.json.j210
-rw-r--r--src/onapsdk/so/templates/instantiate_network_vnf_ala_carte_base.json.j244
-rw-r--r--src/onapsdk/so/templates/instantiate_service_ala_carte.json.j245
-rw-r--r--src/onapsdk/so/templates/instantiate_service_macro.json.j2173
-rw-r--r--src/onapsdk/so/templates/instantiate_vf_module_ala_carte.json.j266
-rw-r--r--src/onapsdk/so/templates/instantiate_vnf_ala_carte.json.j218
-rw-r--r--src/onapsdk/so/templates/instantiate_vnf_macro.json.j2153
-rw-r--r--src/onapsdk/so/templates/instantiate_vnf_macro_so_vnf.json.j2151
-rw-r--r--src/onapsdk/so/templates/service_instance_model_info.json.j27
-rw-r--r--src/onapsdk/so/templates/vf_model_info.json.j215
-rw-r--r--src/onapsdk/so/templates/vnf_model_info.json.j29
22 files changed, 2392 insertions, 0 deletions
diff --git a/src/onapsdk/so/__init__.py b/src/onapsdk/so/__init__.py
new file mode 100644
index 0000000..15a483f
--- /dev/null
+++ b/src/onapsdk/so/__init__.py
@@ -0,0 +1,14 @@
+"""ONAP SDK SO package."""
+# Copyright 2022 Orange, Deutsche Telekom AG
+#
+# 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.
diff --git a/src/onapsdk/so/deletion.py b/src/onapsdk/so/deletion.py
new file mode 100644
index 0000000..35ff0ee
--- /dev/null
+++ b/src/onapsdk/so/deletion.py
@@ -0,0 +1,167 @@
+"""Deletion module."""
+# Copyright 2022 Orange, Deutsche Telekom AG
+#
+# 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.
+from abc import ABC
+
+from onapsdk.onap_service import OnapService
+from onapsdk.utils.headers_creator import headers_so_creator
+from onapsdk.utils.jinja import jinja_env
+
+from onapsdk.so.so_element import OrchestrationRequest
+
+
+class DeletionRequest(OrchestrationRequest, ABC):
+ """Deletion request base class."""
+
+ @classmethod
+ def send_request(cls, instance: "AaiResource", a_la_carte: bool = True) -> "Deletion":
+ """Abstract method to send instance deletion request.
+
+ Raises:
+ NotImplementedError: Needs to be implemented in inheriting classes
+
+ """
+ raise NotImplementedError
+
+
+class VfModuleDeletionRequest(DeletionRequest): # pytest: disable=too-many-ancestors
+ """VF module deletion class."""
+
+ @classmethod
+ def send_request(cls,
+ instance: "VfModuleInstance",
+ a_la_carte: bool = True) -> "VfModuleDeletion":
+ """Send request to SO to delete VNF instance.
+
+ Args:
+ instance (VfModuleInstance): Vf Module instance to delete
+ a_la_carte (boolean): deletion mode
+
+ Returns:
+ VnfDeletionRequest: Deletion request object
+
+ """
+ cls._logger.debug("VF module %s deletion request", instance.vf_module_id)
+ response = cls.send_message_json("DELETE",
+ (f"Create {instance.vf_module_id} VF module"
+ "deletion request"),
+ (f"{cls.base_url}/onap/so/infra/"
+ f"serviceInstantiation/{cls.api_version}/"
+ "serviceInstances/"
+ f"{instance.vnf_instance.service_instance.instance_id}/"
+ f"vnfs/{instance.vnf_instance.vnf_id}/"
+ f"vfModules/{instance.vf_module_id}"),
+ data=jinja_env().
+ get_template("deletion_vf_module.json.j2").
+ render(vf_module_instance=instance,
+ a_la_carte=a_la_carte),
+ headers=headers_so_creator(OnapService.headers))
+ return cls(request_id=response["requestReferences"]["requestId"])
+
+
+class VnfDeletionRequest(DeletionRequest): # pytest: disable=too-many-ancestors
+ """VNF deletion class."""
+
+ @classmethod
+ def send_request(cls,
+ instance: "VnfInstance",
+ a_la_carte: bool = True) -> "VnfDeletionRequest":
+ """Send request to SO to delete VNF instance.
+
+ Args:
+ instance (VnfInstance): VNF instance to delete
+ a_la_carte (boolean): deletion mode
+
+ Returns:
+ VnfDeletionRequest: Deletion request object
+
+ """
+ cls._logger.debug("VNF %s deletion request", instance.vnf_id)
+ response = cls.send_message_json("DELETE",
+ f"Create {instance.vnf_id} VNF deletion request",
+ (f"{cls.base_url}/onap/so/infra/"
+ f"serviceInstantiation/{cls.api_version}/"
+ "serviceInstances/"
+ f"{instance.service_instance.instance_id}/"
+ f"vnfs/{instance.vnf_id}"),
+ data=jinja_env().
+ get_template("deletion_vnf.json.j2").
+ render(vnf_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."""
+
+ @classmethod
+ def send_request(cls,
+ instance: "ServiceInstance",
+ a_la_carte: bool = True) -> "ServiceDeletionRequest":
+ """Send request to SO to delete service instance.
+
+ Args:
+ instance (ServiceInstance): service instance to delete
+ a_la_carte (boolean): deletion mode
+
+ Returns:
+ ServiceDeletionRequest: Deletion request object
+
+ """
+ cls._logger.debug("Service %s deletion request", instance.instance_id)
+ response = cls.send_message_json("DELETE",
+ f"Create {instance.instance_id} Service deletion request",
+ (f"{cls.base_url}/onap/so/infra/"
+ f"serviceInstantiation/{cls.api_version}/"
+ f"serviceInstances/{instance.instance_id}"),
+ data=jinja_env().
+ get_template("deletion_service.json.j2").
+ render(service_instance=instance,
+ a_la_carte=a_la_carte),
+ headers=headers_so_creator(OnapService.headers))
+ return cls(request_id=response["requestReferences"]["requestId"])
+
+
+class NetworkDeletionRequest(DeletionRequest): # pylint: disable=too-many-ancestors
+ """Network deletion request class."""
+
+ @classmethod
+ def send_request(cls,
+ instance: "NetworkInstance",
+ a_la_carte: bool = True) -> "VnfDeletionRequest":
+ """Send request to SO to delete Network instance.
+
+ Args:
+ instance (NetworkInstance): Network instance to delete
+ a_la_carte (boolean): deletion mode
+
+ Returns:
+ NetworkDeletionRequest: Deletion request object
+
+ """
+ cls._logger.debug("Network %s deletion request", instance.network_id)
+ response = cls.send_message_json("DELETE",
+ f"Create {instance.network_id} Network deletion request",
+ (f"{cls.base_url}/onap/so/infra/"
+ f"serviceInstantiation/{cls.api_version}/"
+ "serviceInstances/"
+ f"{instance.service_instance.instance_id}/"
+ f"networks/{instance.network_id}"),
+ data=jinja_env().
+ get_template("deletion_network.json.j2").
+ render(network_instance=instance,
+ a_la_carte=a_la_carte),
+ headers=headers_so_creator(OnapService.headers))
+ return cls(request_id=response["requestReferences"]["requestId"])
diff --git a/src/onapsdk/so/instantiation.py b/src/onapsdk/so/instantiation.py
new file mode 100644
index 0000000..bb0bde2
--- /dev/null
+++ b/src/onapsdk/so/instantiation.py
@@ -0,0 +1,957 @@
+"""Instantion module."""
+# Copyright 2022 Orange, Deutsche Telekom AG
+#
+# 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.
+from abc import ABC
+from dataclasses import dataclass, field
+from typing import Any, Dict, Iterable, List, Optional
+from uuid import uuid4
+from dacite import from_dict
+
+from onapsdk.aai.business.owning_entity import OwningEntity
+from onapsdk.exceptions import (
+ APIError, InvalidResponse, ParameterError, ResourceNotFound, StatusError
+)
+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.utils.jinja import jinja_env
+from onapsdk.utils.headers_creator import headers_so_creator
+from onapsdk.configuration import settings
+
+from .so_element import OrchestrationRequest
+
+
+@dataclass
+class Operation:
+ """Operation class with data about method and suffix for VnfOperation."""
+
+ request_method: str
+ request_suffix: str
+
+
+class VnfOperation(Operation): # pylint: disable=too-few-public-methods
+ """Class to store possible operations' data for vnfs (request method and suffix)."""
+
+ UPDATE = Operation("PUT", "")
+ HEALTHCHECK = Operation("POST", "/healthcheck")
+
+
+@dataclass
+class SoServiceVfModule:
+ """Class to store a VfModule instance parameters."""
+
+ model_name: str
+ instance_name: str
+ parameters: Dict[str, Any] = field(default_factory=dict)
+ processing_priority: Optional[int] = None
+
+
+@dataclass
+class SoServiceXnf:
+ """Class to store a Xnf instance parameters."""
+
+ model_name: str
+ instance_name: str
+ parameters: Dict[str, Any] = field(default_factory=dict)
+ processing_priority: Optional[int] = None
+
+ @classmethod
+ def load(cls, data: Dict[str, Any]) -> "SoServiceVnf":
+ """Create a vnf instance description object from the dict.
+
+ Useful if you keep your instance data in file.
+
+ Returns:
+ SoServiceVnf: SoServiceVnf object created from the dictionary
+
+ """
+ return from_dict(data_class=cls, data=data)
+
+
+@dataclass
+class SoServiceVnf(SoServiceXnf):
+ """Class to store a Vnf instance parameters."""
+
+ vf_modules: List[SoServiceVfModule] = field(default_factory=list)
+
+
+@dataclass
+class SoServicePnf(SoServiceXnf):
+ """Class to store a Pnf instance parameters."""
+
+
+@dataclass
+class SoService:
+ """Class to store SO Service parameters used for macro instantiation.
+
+ Contains value list: List of vnfs to instantiate
+ Contains value: subscription service type
+ """
+
+ subscription_service_type: str
+ vnfs: List[SoServiceVnf] = field(default_factory=list)
+ pnfs: List[SoServicePnf] = field(default_factory=list)
+ instance_name: Optional[str] = None
+
+ @classmethod
+ def load(cls, data: Dict[str, Any]) -> "SoService":
+ """Create a service instance description object from the dict.
+
+ Useful if you keep your instance data in file.
+
+ Returns:
+ SoService: SoService object created from the dictionary
+
+ """
+ return from_dict(data_class=cls, data=data)
+
+
+
+@dataclass
+class VnfParameters:
+ """Class to store vnf parameters used for macro instantiation.
+
+ Contains value lists: List vnf Instantiation parameters and list of
+ vfModule parameters
+ """
+
+ name: str
+ vnf_parameters: Iterable["InstantiationParameter"] = None
+ vfmodule_parameters: Iterable["VfmoduleParameters"] = None
+
+@dataclass
+class VfmoduleParameters:
+ """Class to store vfmodule parameters used for macro instantiation.
+
+ Contains value lists: List of vfModule parameters
+ """
+
+ name: str
+ vfmodule_parameters: Iterable["InstantiationParameter"] = None
+
+
+@dataclass
+class InstantiationParameter:
+ """Class to store instantiation parameters used for preload or macro instantiation.
+
+ Contains two values: name of parameter and it's value
+ """
+
+ name: str
+ value: str
+
+
+@dataclass
+class Subnet: # pylint: disable=too-many-instance-attributes
+ """Class to store subnet parameters used for preload."""
+
+ name: str
+ start_address: str
+ gateway_address: str
+ role: str = None
+ cidr_mask: str = "24"
+ ip_version: str = "4"
+ dhcp_enabled: bool = False
+ dhcp_start_address: Optional[str] = None
+ dhcp_end_address: Optional[str] = None
+
+ def __post_init__(self) -> None:
+ """Post init subnet method.
+
+ Checks if both dhcp_start_address and dhcp_end_address values are
+ provided if dhcp is enabled.
+
+ Raises:
+ ParameterError: Neither dhcp_start_addres
+ nor dhcp_end_address are provided
+
+ """
+ if self.dhcp_enabled and \
+ not all([self.dhcp_start_address,
+ self.dhcp_end_address]):
+ msg = "DHCP is enabled but neither DHCP " \
+ "start nor end adresses are provided."
+ raise ParameterError(msg)
+
+
+class Instantiation(OrchestrationRequest, ABC):
+ """Abstract class used for instantiation."""
+
+ def __init__(self,
+ name: str,
+ request_id: str,
+ instance_id: str) -> None:
+ """Instantiate object initialization.
+
+ Initializator used by classes inherited from this abstract class.
+
+ Args:
+ name (str): instantiated object name
+ request_id (str): request ID
+ instance_id (str): instance ID
+ """
+ super().__init__(request_id)
+ self.name: str = name
+ self.instance_id: str = instance_id
+
+
+class VfModuleInstantiation(Instantiation): # pytest: disable=too-many-ancestors
+ """VF module instantiation class."""
+
+ def __init__(self,
+ name: str,
+ request_id: str,
+ instance_id: str,
+ vf_module: VfModule) -> None:
+ """Initialize class object.
+
+ Args:
+ name (str): vf module name
+ request_id (str): request ID
+ instance_id (str): instance ID
+ vnf_instantiation (VnfInstantiation): VNF instantiation class object
+ vf_module (VfModule): VF module used for instantiation
+ """
+ super().__init__(name, request_id, instance_id)
+ self.vf_module: VfModule = vf_module
+
+ @classmethod
+ def instantiate_ala_carte(cls, # pylint: disable=too-many-arguments
+ vf_module: "VfModule",
+ vnf_instance: "VnfInstance",
+ cloud_region: "CloudRegion",
+ tenant: "Tenant",
+ vf_module_instance_name: str = None,
+ vnf_parameters: Iterable["InstantiationParameter"] = None,
+ use_preload: bool = True) -> "VfModuleInstantiation":
+ """Instantiate VF module.
+
+ Iterate throught vf modules from service Tosca file and instantiate vf modules.
+
+ Args:
+ vf_module (VfModule): VfModule to instantiate
+ vnf_instance (VnfInstance): VnfInstance object
+ cloud_region (CloudRegion, optional): Cloud region to use in instantiation request.
+ Defaults to None.
+ tenant (Tenant, optional): Tenant to use in instnatiation request.
+ Defaults to None.
+ vf_module_instance_name_factory (str, optional): Factory to create VF module names.
+ It's going to be a prefix of name. Index of vf module in Tosca file will be
+ added to it.
+ If no value is provided it's going to be
+ "Python_ONAP_SDK_vf_module_service_instance_{str(uuid4())}".
+ Defaults to None.
+ vnf_parameters (Iterable[InstantiationParameter], optional): Parameters which are
+ going to be used in preload upload for vf modules or passed in "userParams".
+ Defaults to None.
+ use_preload (bool, optional): This flag determines whether instantiation parameters
+ are used as preload or "userParams" content. Defaults to True
+
+ Yields:
+ Iterator[VfModuleInstantiation]: VfModuleInstantiation class object.
+
+ """
+ if vf_module_instance_name is None:
+ vf_module_instance_name = \
+ f"Python_ONAP_SDK_vf_module_instance_{str(uuid4())}"
+ if use_preload:
+ VfModulePreload.upload_vf_module_preload(
+ vnf_instance,
+ vf_module_instance_name,
+ vf_module,
+ vnf_parameters
+ )
+ vnf_parameters = None
+ sdc_service: SdcService = vnf_instance.service_instance.sdc_service
+ response: dict = cls.send_message_json(
+ "POST",
+ (f"Instantiate {sdc_service.name} "
+ f"service vf module {vf_module.name}"),
+ (f"{cls.base_url}/onap/so/infra/serviceInstantiation/{cls.api_version}/"
+ f"serviceInstances/{vnf_instance.service_instance.instance_id}/vnfs/"
+ f"{vnf_instance.vnf_id}/vfModules"),
+ data=jinja_env().get_template("instantiate_vf_module_ala_carte.json.j2").
+ render(
+ vf_module_instance_name=vf_module_instance_name,
+ vf_module=vf_module,
+ service=sdc_service,
+ cloud_region=cloud_region,
+ tenant=tenant,
+ vnf_instance=vnf_instance,
+ vf_module_parameters=vnf_parameters or []
+ ),
+ headers=headers_so_creator(OnapService.headers)
+ )
+ return VfModuleInstantiation(
+ name=vf_module_instance_name,
+ request_id=response["requestReferences"].get("requestId"),
+ instance_id=response["requestReferences"].get("instanceId"),
+ vf_module=vf_module
+ )
+
+
+class NodeTemplateInstantiation(Instantiation, ABC): # pytest: disable=too-many-ancestors
+ """Base class for service's node_template object instantiation."""
+
+ def __init__(self, # pylint: disable=too-many-arguments
+ name: str,
+ request_id: str,
+ instance_id: str,
+ line_of_business: str,
+ platform: str) -> None:
+ """Node template object initialization.
+
+ Args:
+ name (str): Node template name
+ request_id (str): Node template instantiation request ID
+ instance_id (str): Node template instance ID
+ line_of_business (str): LineOfBusiness name
+ platform (str): Platform name
+ """
+ super().__init__(name, request_id, instance_id)
+ self.line_of_business = line_of_business
+ self.platform = platform
+
+
+class VnfInstantiation(NodeTemplateInstantiation): # pylint: disable=too-many-ancestors
+ """VNF instantiation class."""
+
+ def __init__(self, # pylint: disable=too-many-arguments
+ name: str,
+ request_id: str,
+ instance_id: str,
+ line_of_business: str,
+ platform: str,
+ vnf: Vnf) -> None:
+ """Class VnfInstantion object initialization.
+
+ Args:
+ name (str): VNF 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
+ vnf (Vnf): Vnf class object
+ """
+ super().__init__(name, request_id, instance_id, line_of_business, platform)
+ self.vnf = vnf
+
+ @classmethod
+ def create_from_request_response(cls, request_response: dict) -> "VnfInstantiation":
+ """Create VNF instantiation object based on request details.
+
+ Raises:
+ ResourceNotFound: Service related with given object doesn't exist
+ ResourceNotFound: No ServiceInstantiation related with given VNF instantiation
+ ResourceNotFound: VNF related with given object doesn't exist
+ InvalidResponse: Invalid dictionary - couldn't create VnfInstantiation object
+
+ Returns:
+ VnfInstantiation: VnfInstantiation object
+
+ """
+ if request_response.get("request", {}).get("requestScope") == "vnf" 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 Vnf instance details response")
+ vnf: Vnf = None
+ for service_vnf in service.vnfs:
+ if service_vnf.name == request_response.get("request", {})\
+ .get("requestDetails", {}).get("modelInfo", {}).get("modelCustomizationName"):
+ vnf = service_vnf
+ if not vnf:
+ raise ResourceNotFound("No vnf in service vnfs list")
+ return cls(
+ name=request_response.get("request", {})\
+ .get("instanceReferences", {}).get("vnfInstanceName"),
+ request_id=request_response.get("request", {}).get("requestId"),
+ instance_id=request_response.get("request", {})\
+ .get("instanceReferences", {}).get("vnfInstanceId"),
+ line_of_business=request_response.get("request", {})\
+ .get("requestDetails", {}).get("lineOfBusiness", {}).get("lineOfBusinessName"),
+ platform=request_response.get("request", {})\
+ .get("requestDetails", {}).get("platform", {}).get("platformName"),
+ vnf=vnf
+ )
+ raise InvalidResponse("Invalid vnf instantions in response dictionary's requestList")
+
+ @classmethod
+ def get_by_vnf_instance_name(cls, vnf_instance_name: str) -> "VnfInstantiation":
+ """Get VNF instantiation request by instance name.
+
+ Raises:
+ InvalidResponse: Vnf instance with given name does not contain
+ requestList or the requestList does not contain any details.
+
+ Returns:
+ VnfInstantiation: Vnf instantiation request object
+
+ """
+ response: dict = cls.send_message_json(
+ "GET",
+ f"Check {vnf_instance_name} service instantiation status",
+ (f"{cls.base_url}/onap/so/infra/orchestrationRequests/{cls.api_version}?"
+ f"filter=vnfInstanceName:EQUALS:{vnf_instance_name}"),
+ headers=headers_so_creator(OnapService.headers)
+ )
+ key = "requestList"
+ if not response.get(key, []):
+ raise InvalidResponse(f"{key} of a Vnf 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_ala_carte(cls, # pylint: disable=too-many-arguments
+ aai_service_instance: "ServiceInstance",
+ vnf_object: "Vnf",
+ line_of_business: str,
+ platform: str,
+ cloud_region: "CloudRegion",
+ tenant: "Tenant",
+ sdc_service: "SdcService",
+ vnf_instance_name: str = None,
+ vnf_parameters: Iterable["InstantiationParameter"] = None
+ ) -> "VnfInstantiation":
+ """Instantiate Vnf using a'la carte method.
+
+ Args:
+ vnf_object (Vnf): Vnf to instantiate
+ line_of_business_object (LineOfBusiness): LineOfBusiness to use in instantiation request
+ platform_object (Platform): Platform to use in instantiation request
+ cloud_region (CloudRegion): Cloud region to use in instantiation request.
+ tenant (Tenant): Tenant to use in instnatiation request.
+ vnf_instance_name (str, optional): Vnf instance name. Defaults to None.
+ vnf_parameters (Iterable[InstantiationParameter], optional): Instantiation parameters
+ that are sent in the request. Defaults to None
+
+ Returns:
+ VnfInstantiation: VnfInstantiation object
+
+ """
+ if vnf_instance_name is None:
+ vnf_instance_name = \
+ f"Python_ONAP_SDK_vnf_instance_{str(uuid4())}"
+ response: dict = cls.send_message_json(
+ "POST",
+ (f"Instantiate {sdc_service.name} "
+ f"service vnf {vnf_object.name}"),
+ (f"{cls.base_url}/onap/so/infra/serviceInstantiation/{cls.api_version}/"
+ f"serviceInstances/{aai_service_instance.instance_id}/vnfs"),
+ data=jinja_env().get_template("instantiate_vnf_ala_carte.json.j2").
+ render(
+ instance_name=vnf_instance_name,
+ vnf=vnf_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),
+ line_of_business=line_of_business,
+ platform=platform,
+ service_instance=aai_service_instance,
+ vnf_parameters=vnf_parameters or []
+ ),
+ headers=headers_so_creator(OnapService.headers)
+ )
+ return VnfInstantiation(
+ name=vnf_instance_name,
+ request_id=response["requestReferences"]["requestId"],
+ instance_id=response["requestReferences"]["instanceId"],
+ line_of_business=line_of_business,
+ platform=platform,
+ vnf=vnf_object
+ )
+
+ @classmethod
+ def instantiate_macro(cls, # pylint: disable=too-many-arguments, too-many-locals
+ aai_service_instance: "ServiceInstance",
+ vnf_object: "Vnf",
+ line_of_business: str,
+ platform: str,
+ cloud_region: "CloudRegion",
+ tenant: "Tenant",
+ sdc_service: "SdcService",
+ vnf_instance_name: str = None,
+ vnf_parameters: Iterable["InstantiationParameter"] = None,
+ so_vnf: "SoServiceVnf" = None
+ ) -> "VnfInstantiation":
+ """Instantiate Vnf using macro method.
+
+ Args:
+ aai_service_instance (ServiceInstance): Service instance associated with request
+ vnf_object (Vnf): Vnf 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.
+ vnf_instance_name (str, optional): Vnf instance name. Defaults to None.
+ vnf_parameters (Iterable[InstantiationParameter], optional): Instantiation parameters
+ that are sent in the request. Defaults to None
+ so_vnf (SoServiceVnf): object with vnf instance parameters
+
+ Returns:
+ VnfInstantiation: VnfInstantiation 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_vnf:
+ template_file = "instantiate_vnf_macro_so_vnf.json.j2"
+ if so_vnf.instance_name:
+ vnf_instance_name = so_vnf.instance_name
+ else:
+ template_file = "instantiate_vnf_macro.json.j2"
+ if vnf_instance_name is None:
+ vnf_instance_name = \
+ f"Python_ONAP_SDK_vnf_instance_{str(uuid4())}"
+
+ response: dict = cls.send_message_json(
+ "POST",
+ (f"Instantiate {sdc_service.name} "
+ f"service vnf {vnf_object.name}"),
+ (f"{cls.base_url}/onap/so/infra/serviceInstantiation/{cls.api_version}/"
+ f"serviceInstances/{aai_service_instance.instance_id}/vnfs"),
+ data=jinja_env().get_template(template_file).render(
+ instance_name=vnf_instance_name,
+ vnf=vnf_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,
+ vnf_parameters=vnf_parameters or [],
+ so_vnf=so_vnf
+ ),
+ headers=headers_so_creator(OnapService.headers)
+ )
+
+ return VnfInstantiation(
+ name=vnf_instance_name,
+ request_id=response["requestReferences"]["requestId"],
+ instance_id=response["requestReferences"]["instanceId"],
+ line_of_business=line_of_business,
+ platform=platform,
+ vnf=vnf_object
+ )
+
+ @classmethod
+ def so_action(cls, # pylint: disable=too-many-arguments, too-many-locals
+ vnf_instance: "VnfInstance",
+ operation_type: VnfOperation,
+ aai_service_instance: "ServiceInstance",
+ line_of_business: str,
+ platform: str,
+ sdc_service: "SdcService",
+ so_service: "SoService" = None
+ ) -> "VnfInstantiation":
+ """Execute SO action (update or healthcheck) for selected vnf with SO macro request.
+
+ Args:
+ vnf_instance (VnfInstance): vnf instance 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
+ in instantiation request
+ platform (Platform): Platform name to use in instantiation request
+ sdc_service (SdcService): Service model information
+ so_service (SoService, optional): SO values to use in SO request
+
+ Raises:
+ StatusError: if the provided operation is not supported
+
+ Returns:
+ VnfInstantiation: VnfInstantiation object
+
+ """
+ if operation_type not in (VnfOperation.HEALTHCHECK, VnfOperation.UPDATE):
+ 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_type.request_method,
+ (f"So Action {sdc_service.name} "
+ f" vnf instance {vnf_instance.vnf_id}"),
+ (f"{cls.base_url}/onap/so/infra/serviceInstantiation/{cls.api_version}/"
+ f"serviceInstances/{aai_service_instance.instance_id}/vnfs/{vnf_instance.vnf_id}"
+ f"{operation_type.request_suffix}"),
+ data=jinja_env().get_template("instantiate_multi_vnf_service_macro.json.j2").render(
+ sdc_service=sdc_service,
+ cloud_region=next(aai_service_instance.service_subscription.cloud_regions),
+ tenant=next(aai_service_instance.service_subscription.tenants),
+ customer=aai_service_instance.service_subscription.customer,
+ project=project,
+ owning_entity=owning_entity,
+ line_of_business=line_of_business,
+ platform=platform,
+ service_instance_name=aai_service_instance.instance_name,
+ so_service=so_service
+ ),
+ headers=headers_so_creator(OnapService.headers)
+ )
+
+ return VnfInstantiation(
+ name=vnf_instance.vnf_name,
+ request_id=response["requestReferences"]["requestId"],
+ instance_id=response["requestReferences"]["instanceId"],
+ line_of_business=line_of_business,
+ platform=platform,
+ vnf=vnf_instance
+ )
+
+
+class ServiceInstantiation(Instantiation): # pylint: disable=too-many-ancestors
+ """Service instantiation class."""
+
+ def __init__(self, # pylint: disable=too-many-arguments
+ name: str,
+ request_id: str,
+ instance_id: str,
+ sdc_service: "SdcService",
+ cloud_region: "CloudRegion",
+ tenant: "Tenant",
+ customer: "Customer",
+ owning_entity: OwningEntity,
+ project: str) -> None:
+ """Class ServiceInstantiation object initialization.
+
+ Args:
+ name (str): service instance name
+ request_id (str): service instantiation request ID
+ instance_id (str): service instantiation ID
+ sdc_service (SdcService): SdcService class object
+ cloud_region (CloudRegion): CloudRegion class object
+ tenant (Tenant): Tenant class object
+ customer (Customer): Customer class object
+ owning_entity (OwningEntity): OwningEntity class object
+ project (str): Project name
+
+ """
+ super().__init__(name, request_id, instance_id)
+ self.sdc_service = sdc_service
+ self.cloud_region = cloud_region
+ self.tenant = tenant
+ self.customer = customer
+ self.owning_entity = owning_entity
+ self.project = project
+
+ @classmethod
+ def instantiate_ala_carte(cls, # pylint: disable=too-many-arguments
+ sdc_service: "SdcService",
+ cloud_region: "CloudRegion",
+ tenant: "Tenant",
+ customer: "Customer",
+ owning_entity: OwningEntity,
+ project: str,
+ service_subscription: "ServiceSubscription",
+ service_instance_name: str = None,
+ enable_multicloud: bool = False) -> "ServiceInstantiation":
+ """Instantiate service using SO a'la carte request.
+
+ Args:
+ sdc_service (SdcService): Service to instantiate
+ cloud_region (CloudRegion): Cloud region to use in instantiation request
+ tenant (Tenant): Tenant to use in instantiation request
+ customer (Customer): Customer to use in instantiation request
+ owning_entity (OwningEntity): Owning entity to use in instantiation request
+ project (str): Project name to use in instantiation request
+ service_subscription (ServiceSubscription): Customer's service subsription.
+ service_instance_name (str, optional): Service instance name. Defaults to None.
+ enable_multicloud (bool, optional): Determines if Multicloud should be enabled
+ for instantiation request. Defaults to False.
+
+ Raises:
+ StatusError: if a service is not distributed.
+
+ Returns:
+ ServiceInstantiation: instantiation request object
+
+ """
+ if not sdc_service.distributed:
+ msg = f"Service {sdc_service.name} is not distributed."
+ raise StatusError(msg)
+ if service_instance_name is None:
+ service_instance_name = f"Python_ONAP_SDK_service_instance_{str(uuid4())}"
+ response: dict = cls.send_message_json(
+ "POST",
+ f"Instantiate {sdc_service.name} service a'la carte",
+ (f"{cls.base_url}/onap/so/infra/"
+ f"serviceInstantiation/{cls.api_version}/serviceInstances"),
+ data=jinja_env().get_template("instantiate_service_ala_carte.json.j2").
+ render(
+ sdc_service=sdc_service,
+ cloud_region=cloud_region,
+ tenant=tenant,
+ customer=customer,
+ owning_entity=owning_entity,
+ service_instance_name=service_instance_name,
+ project=project,
+ enable_multicloud=enable_multicloud,
+ service_subscription=service_subscription
+ ),
+ headers=headers_so_creator(OnapService.headers)
+ )
+ return cls(
+ name=service_instance_name,
+ request_id=response["requestReferences"].get("requestId"),
+ instance_id=response["requestReferences"].get("instanceId"),
+ sdc_service=sdc_service,
+ cloud_region=cloud_region,
+ tenant=tenant,
+ customer=customer,
+ owning_entity=owning_entity,
+ project=project
+ )
+
+ # pylint: disable=too-many-arguments, too-many-locals
+ @classmethod
+ def instantiate_macro(cls,
+ sdc_service: "SdcService",
+ customer: "Customer",
+ owning_entity: OwningEntity,
+ project: str,
+ line_of_business: str,
+ platform: str,
+ aai_service: "AaiService" = None,
+ cloud_region: "CloudRegion" = None,
+ tenant: "Tenant" = None,
+ service_instance_name: str = None,
+ vnf_parameters: Iterable["VnfParameters"] = None,
+ enable_multicloud: bool = False,
+ so_service: "SoService" = None,
+ service_subscription: "ServiceSubscription" = None
+ ) -> "ServiceInstantiation":
+ """Instantiate service using SO macro request.
+
+ Args:
+ sdc_service (SdcService): Service to instantiate
+ customer (Customer): Customer to use in instantiation request
+ owning_entity (OwningEntity): Owning entity to use in instantiation request
+ project (Project): Project name to use in instantiation request
+ line_of_business_object (LineOfBusiness): LineOfBusiness name to use
+ in instantiation request
+ platform_object (Platform): Platform name to use in instantiation request
+ aai_service (AaiService): Service object from aai sdc
+ cloud_region (CloudRegion): Cloud region to use in instantiation request
+ tenant (Tenant): Tenant to use in instantiation request
+ service_instance_name (str, optional): Service instance name. Defaults to None.
+ vnf_parameters: (Iterable[VnfParameters]): Parameters which are
+ going to be used for vnfs instantiation. Defaults to None.
+ enable_multicloud (bool, optional): Determines if Multicloud should be enabled
+ for instantiation request. Defaults to False.
+ so_service (SoService, optional): SO values to use in instantiation request
+ service_subscription(ServiceSubscription, optional): Customer service subscription
+ for the instantiated service. Required if so_service is not provided.
+
+ Raises:
+ StatusError: if a service is not distributed.
+
+ Returns:
+ ServiceInstantiation: instantiation request object
+
+ """
+ template_file = "instantiate_service_macro.json.j2"
+ if so_service:
+ template_file = "instantiate_multi_vnf_service_macro.json.j2"
+ if so_service.instance_name:
+ service_instance_name = so_service.instance_name
+ else:
+ if not service_subscription:
+ raise ParameterError("If no so_service is provided, "
+ "service_subscription parameter is required!")
+ if service_instance_name is None:
+ service_instance_name = f"Python_ONAP_SDK_service_instance_{str(uuid4())}"
+ if not sdc_service.distributed:
+ msg = f"Service {sdc_service.name} is not distributed."
+ raise StatusError(msg)
+
+ response: dict = cls.send_message_json(
+ "POST",
+ f"Instantiate {sdc_service.name} service macro",
+ (f"{cls.base_url}/onap/so/infra/"
+ f"serviceInstantiation/{cls.api_version}/serviceInstances"),
+ data=jinja_env().get_template(template_file). \
+ render(
+ so_service=so_service,
+ sdc_service=sdc_service,
+ cloud_region=cloud_region,
+ tenant=tenant,
+ customer=customer,
+ owning_entity=owning_entity,
+ project=project,
+ aai_service=aai_service,
+ line_of_business=line_of_business,
+ platform=platform,
+ service_instance_name=service_instance_name,
+ vnf_parameters=vnf_parameters,
+ enable_multicloud=enable_multicloud,
+ service_subscription=service_subscription
+ ),
+ headers=headers_so_creator(OnapService.headers)
+ )
+ return cls(
+ name=service_instance_name,
+ request_id=response["requestReferences"].get("requestId"),
+ instance_id=response["requestReferences"].get("instanceId"),
+ sdc_service=sdc_service,
+ cloud_region=cloud_region,
+ tenant=tenant,
+ customer=customer,
+ owning_entity=owning_entity,
+ project=project
+ )
+
+ @property
+ def aai_service_instance(self) -> "ServiceInstance":
+ """Service instance associated with service instantiation request.
+
+ Raises:
+ StatusError: if a service is not instantiated -
+ not in COMPLETE status.
+ APIError: A&AI resource is not created
+
+ Returns:
+ ServiceInstance: ServiceInstance
+
+ """
+ required_status = self.StatusEnum.COMPLETED
+ if self.status != required_status:
+ msg = (f"Service {self.name} is not instantiated - "
+ f"not in {required_status} status.")
+ raise StatusError(msg)
+ try:
+ service_subscription: "ServiceSubscription" = \
+ self.customer.get_service_subscription_by_service_type(self.sdc_service.name)
+ return service_subscription.get_service_instance_by_name(self.name)
+ except APIError as exc:
+ self._logger.error("A&AI resources not created properly")
+ raise exc
+
+
+class NetworkInstantiation(NodeTemplateInstantiation): # pylint: disable=too-many-ancestors
+ """Network instantiation class."""
+
+ def __init__(self, # pylint: disable=too-many-arguments
+ name: str,
+ request_id: str,
+ instance_id: str,
+ line_of_business: str,
+ platform: str,
+ network: Network) -> None:
+ """Class NetworkInstantiation object initialization.
+
+ Args:
+ name (str): VNF 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
+ vnf (Network): Network class object
+ """
+ super().__init__(name, request_id, instance_id, line_of_business, platform)
+ self.network = network
+
+ @classmethod
+ def instantiate_ala_carte(cls, # pylint: disable=too-many-arguments
+ aai_service_instance: "ServiceInstance",
+ network_object: "Network",
+ line_of_business: str,
+ platform: str,
+ cloud_region: "CloudRegion",
+ tenant: "Tenant",
+ network_instance_name: str = None,
+ subnets: Iterable[Subnet] = None) -> "NetworkInstantiation":
+ """Instantiate Network using a'la carte method.
+
+ Args:
+ network_object (Network): Network to instantiate
+ line_of_business (str): LineOfBusiness name to use in instantiation request
+ platform (str): Platform name to use in instantiation request
+ cloud_region (CloudRegion): Cloud region to use in instantiation request.
+ tenant (Tenant): Tenant to use in instnatiation request.
+ network_instance_name (str, optional): Network instance name. Defaults to None.
+
+ Returns:
+ NetworkInstantiation: NetworkInstantiation object
+
+ """
+ if network_instance_name is None:
+ network_instance_name = \
+ f"Python_ONAP_SDK_network_instance_{str(uuid4())}"
+ NetworkPreload.upload_network_preload(network=network_object,
+ network_instance_name=network_instance_name,
+ subnets=subnets)
+ response: dict = cls.send_message_json(
+ "POST",
+ (f"Instantiate {aai_service_instance.sdc_service.name} "
+ f"service network {network_object.name}"),
+ (f"{cls.base_url}/onap/so/infra/serviceInstantiation/{cls.api_version}/"
+ f"serviceInstances/{aai_service_instance.instance_id}/networks"),
+ data=jinja_env().get_template("instantiate_network_ala_carte.json.j2").
+ render(
+ instance_name=network_instance_name,
+ network=network_object,
+ service=aai_service_instance.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),
+ line_of_business=line_of_business,
+ platform=platform,
+ service_instance=aai_service_instance,
+ subnets=subnets
+ ),
+ headers=headers_so_creator(OnapService.headers)
+ )
+ return cls(
+ name=network_instance_name,
+ request_id=response["requestReferences"]["requestId"],
+ instance_id=response["requestReferences"]["instanceId"],
+ line_of_business=line_of_business,
+ platform=platform,
+ network=network_object
+ )
diff --git a/src/onapsdk/so/so_db_adapter.py b/src/onapsdk/so/so_db_adapter.py
new file mode 100644
index 0000000..b3694d1
--- /dev/null
+++ b/src/onapsdk/so/so_db_adapter.py
@@ -0,0 +1,94 @@
+"""Database Adapter module."""
+# Copyright 2022 Orange, Deutsche Telekom AG
+#
+# 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.
+from abc import ABC
+from dataclasses import dataclass
+from typing import Dict, Any
+
+from onapsdk.so.so_element import SoElement
+from onapsdk.onap_service import OnapService
+from onapsdk.utils.headers_creator import headers_so_creator, headers_so_catelog_db_creator
+from onapsdk.utils.jinja import jinja_env
+
+
+@dataclass
+class IdentityService: # pylint: disable=too-many-instance-attributes
+ """Class to store identity service details."""
+
+ identity_id: str
+ url: str = "http://1.2.3.4:5000/v2.0"
+ mso_id: str = "onapsdk_user"
+ mso_pass: str = "mso_pass_onapsdk"
+ project_domain_name: str = "NULL"
+ user_domain_name: str = "NULL"
+ admin_tenant: str = "service"
+ member_role: str = "admin"
+ identity_server_type: str = "KEYSTONE"
+ identity_authentication_type: str = "USERNAME_PASSWORD"
+ hibernate_lazy_initializer = {}
+ server_type_as_string: str = "KEYSTONE"
+ tenant_metadata: bool = True
+
+
+class SoDbAdapter(SoElement, ABC):
+ """DB Adapter class."""
+
+ @classmethod
+ def add_cloud_site(cls,
+ cloud_region_id: str,
+ complex_id: str,
+ identity_service: IdentityService,
+ orchestrator: str = "multicloud"
+ ):
+ """Add cloud_site data with identity_service to SO db.
+
+ Args:
+ cloud_region_id (str): The id of cloud region
+ complex_id (str): The id of complex
+ identity_service (IdentityService): Identity service related to the cloud region
+ orchestrator (str, optional): Orchestrator type. Defaults to multicloud.
+
+ Important:
+ identity_services data will be overwrite, but in the same time
+ cloud_sites data will not (shouldn't) be overwrite!
+ SOCatalogDB REST API has some limitations reported: https://jira.onap.org/browse/SO-2727
+
+ Return:
+ response object
+ """
+ response = cls.send_message_json(
+ "POST",
+ "Create a region in SO db",
+ f"{cls.base_url}/cloudSite",
+ data=jinja_env().get_template("add_cloud_site_with_identity_service.json.j2").
+ render(
+ cloud_region_id=cloud_region_id,
+ complex_id=complex_id,
+ orchestrator=orchestrator,
+ identity_service=identity_service
+ ),
+ headers=headers_so_creator(OnapService.headers)
+ )
+ return response
+ @classmethod
+ def get_service_vnf_info(cls, identifier: str) -> Dict[Any, Any]:
+ """Get Service VNF and VF details.
+
+ Returns:
+ The response in a dict format
+
+ """
+ url = f"{cls.base_url}/ecomp/mso/catalog/v2/serviceVnfs?serviceModelUuid={identifier}"
+ headers = headers_so_catelog_db_creator(OnapService.headers)
+ return cls.send_message_json("GET", "Get Service Details", url, headers=headers)
diff --git a/src/onapsdk/so/so_element.py b/src/onapsdk/so/so_element.py
new file mode 100644
index 0000000..fca6ba7
--- /dev/null
+++ b/src/onapsdk/so/so_element.py
@@ -0,0 +1,223 @@
+"""SO Element module."""
+# Copyright 2022 Orange, Deutsche Telekom AG
+#
+# 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 json
+from abc import ABC
+from dataclasses import dataclass
+from enum import Enum
+from typing import Dict
+
+from onapsdk.configuration import settings
+from onapsdk.sdc.service import Service
+from onapsdk.sdc.vf import Vf
+from onapsdk.onap_service import OnapService
+from onapsdk.utils.headers_creator import headers_so_creator
+from onapsdk.utils.jinja import jinja_env
+from onapsdk.utils.mixins import WaitForFinishMixin
+from onapsdk.utils.tosca_file_handler import get_modules_list_from_tosca_file
+from onapsdk.utils.gui import GuiItem, GuiList
+
+@dataclass
+class SoElement(OnapService):
+ """Mother Class of all SO elements."""
+
+ name: str = None
+ _server: str = "SO"
+ base_url = settings.SO_URL
+ api_version = settings.SO_API_VERSION
+ _status: str = None
+
+ @property
+ def headers(self):
+ """Create headers for SO request.
+
+ It is used as a property because x-transactionid header should be unique for each request.
+ """
+ return headers_so_creator(OnapService.headers)
+
+ @classmethod
+ def get_subscription_service_type(cls, vf_name):
+ """Retrieve the model info of the VFs."""
+ vf_object = Vf(name=vf_name)
+ return vf_object.name
+
+ @classmethod
+ def get_service_model_info(cls, service_name):
+ """Retrieve Service Model info."""
+ service = Service(name=service_name)
+ template_service = jinja_env().get_template("service_instance_model_info.json.j2")
+ # Get service instance model
+ parsed = json.loads(
+ template_service.render(
+ model_invariant_id=service.unique_uuid,
+ model_name_version_id=service.identifier,
+ model_name=service.name,
+ model_version=service.version,
+ )
+ )
+ return json.dumps(parsed, indent=4)
+
+ @classmethod
+ def get_vnf_model_info(cls, vf_name):
+ """Retrieve the model info of the VFs."""
+ vf_object = Vf(name=vf_name)
+ template_service = jinja_env().get_template("vnf_model_info.json.j2")
+ parsed = json.loads(
+ template_service.render(
+ vnf_model_invariant_uuid=vf_object.unique_uuid,
+ vnf_model_customization_id="????",
+ vnf_model_version_id=vf_object.identifier,
+ vnf_model_name=vf_object.name,
+ vnf_model_version=vf_object.version,
+ vnf_model_instance_name=(vf_object.name + " 0"),
+ )
+ )
+ # we need also a vnf instance Name
+ # Usually it is found like that
+ # name: toto
+ # instance name: toto 0
+ # it can be retrieved from the toscafrom onapsdk.configuration import settings
+ return json.dumps(parsed, indent=4)
+
+ @classmethod
+ def get_vf_model_info(cls, vf_model: str) -> str:
+ """Retrieve the VF model info From Tosca?."""
+ modules: Dict = get_modules_list_from_tosca_file(vf_model)
+ template_service = jinja_env().get_template("vf_model_info.json.j2")
+ parsed = json.loads(template_service.render(modules=modules))
+ return json.dumps(parsed, indent=4)
+
+ @classmethod
+ def _base_create_url(cls) -> str:
+ """
+ Give back the base url of SO.
+
+ Returns:
+ str: the base url
+
+ """
+ return "{}/onap/so/infra/serviceInstantiation/{}/serviceInstances".format(
+ cls.base_url, cls.api_version
+ )
+
+ @classmethod
+ def get_guis(cls) -> GuiItem:
+ """Retrieve the status of the SO GUIs.
+
+ Only one GUI is referenced for SO: SO monitor
+
+ Return the list of GUIs
+ """
+ gui_url = settings.SO_MONITOR_GUI_SERVICE
+ so_gui_response = cls.send_message(
+ "GET", "Get SO GUI Status", gui_url)
+ guilist = GuiList([])
+ guilist.add(GuiItem(
+ gui_url,
+ so_gui_response.status_code))
+ return guilist
+
+
+class OrchestrationRequest(SoElement, WaitForFinishMixin, ABC):
+ """Base SO orchestration request class."""
+
+ WAIT_FOR_SLEEP_TIME = 10
+
+ def __init__(self,
+ request_id: str) -> None:
+ """Instantiate object initialization.
+
+ Initializator used by classes inherited from this abstract class.
+
+ Args:
+ request_id (str): request ID
+ """
+ super().__init__()
+ self.request_id: str = request_id
+
+ class StatusEnum(Enum):
+ """Status enum.
+
+ Store possible statuses for instantiation:
+ - IN_PROGRESS,
+ - FAILED,
+ - COMPLETE.
+ If instantiation has status which is not covered by these values
+ UNKNOWN value is used.
+
+ """
+
+ IN_PROGRESS = "IN_PROGRESS"
+ FAILED = "FAILED"
+ COMPLETED = "COMPLETE"
+ UNKNOWN = "UNKNOWN"
+
+ @property
+ def status(self) -> "StatusEnum":
+ """Object instantiation status.
+
+ It's populated by call SO orchestation request endpoint.
+
+ Returns:
+ StatusEnum: Instantiation status.
+
+ """
+ response: dict = self.send_message_json(
+ "GET",
+ f"Check {self.request_id} orchestration request status",
+ (f"{self.base_url}/onap/so/infra/"
+ f"orchestrationRequests/{self.api_version}/{self.request_id}"),
+ headers=headers_so_creator(OnapService.headers)
+ )
+ try:
+ return self.StatusEnum(response["request"]["requestStatus"]["requestState"])
+ except (KeyError, ValueError):
+ self._logger.exception("Invalid status")
+ return self.StatusEnum.UNKNOWN
+
+ @property
+ def finished(self) -> bool:
+ """Store an information if instantion is finished or not.
+
+ Instantiation is finished if it's status is COMPLETED or FAILED.
+
+ Returns:
+ bool: True if instantiation is finished, False otherwise.
+
+ """
+ return self.status in [self.StatusEnum.COMPLETED, self.StatusEnum.FAILED]
+
+ @property
+ def completed(self) -> bool:
+ """Store an information if instantion is completed or not.
+
+ Instantiation is completed if it's status is COMPLETED.
+
+ Returns:
+ bool: True if instantiation is completed, False otherwise.
+
+ """
+ return self.finished and self.status == self.StatusEnum.COMPLETED
+
+ @property
+ def failed(self) -> bool:
+ """Store an information if instantion is failed or not.
+
+ Instantiation is failed if it's status is FAILED.
+
+ Returns:
+ bool: True if instantiation is failed, False otherwise.
+
+ """
+ return self.finished and self.status == self.StatusEnum.FAILED
diff --git a/src/onapsdk/so/templates/add_cloud_site_with_identity_service.json.j2 b/src/onapsdk/so/templates/add_cloud_site_with_identity_service.json.j2
new file mode 100644
index 0000000..31599f5
--- /dev/null
+++ b/src/onapsdk/so/templates/add_cloud_site_with_identity_service.json.j2
@@ -0,0 +1,22 @@
+{
+ "id": "{{ cloud_region_id }}",
+ "region_id": "{{ cloud_region_id }}",
+ "aic_version": "2.5",
+ "clli": "{{ complex_id }}",
+ "orchestrator": "{{ orchestrator }}",
+ "identityService": {
+ "id": "{{ identity_service.identity_id }}",
+ "identityServerTypeAsString": "{{ identity_service.server_type_as_string }}",
+ "hibernateLazyInitializer": {{ identity_service.hibernate_lazy_initializer }},
+ "identity_url": "{{ identity_service.url }}",
+ "mso_id": "{{ identity_service.mso_id }}",
+ "mso_pass": "{{ identity_service.mso_pass }}",
+ "project_domain_name": "{{ identity_service.project_domain_name }}",
+ "user_domain_name": "{{ identity_service.user_domain_name }}",
+ "admin_tenant": "{{ identity_service.admin_tenant }}",
+ "member_role": "{{ identity_service.member_role }}",
+ "tenant_metadata": "{{ identity_service.tenant_metadata }}",
+ "identity_server_type": "{{ identity_service.identity_server_type }}",
+ "identity_authentication_type": "{{ identity_service.identity_authentication_type }}"
+ }
+} \ No newline at end of file
diff --git a/src/onapsdk/so/templates/deletion_network.json.j2 b/src/onapsdk/so/templates/deletion_network.json.j2
new file mode 100644
index 0000000..93f0990
--- /dev/null
+++ b/src/onapsdk/so/templates/deletion_network.json.j2
@@ -0,0 +1,22 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "source": "VID",
+ "requestorId": "demo"
+ },
+ "modelInfo": {
+ "modelType": "network"
+ },
+ "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": "{{ network_instance.service_instance.service_subscription.cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ network_instance.service_instance.service_subscription.cloud_region.cloud_region_id }}",
+ "tenantId": "{{ network_instance.service_instance.service_subscription.tenant.tenant_id }}"
+ }
+ }
+} \ No newline at end of file
diff --git a/src/onapsdk/so/templates/deletion_service.json.j2 b/src/onapsdk/so/templates/deletion_service.json.j2
new file mode 100644
index 0000000..1244e97
--- /dev/null
+++ b/src/onapsdk/so/templates/deletion_service.json.j2
@@ -0,0 +1,26 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "source": "VID",
+ "requestorId": "demo"
+ },
+ "modelInfo": {
+ "modelType": "service",
+ "modelName": "{{ service_instance.sdc_service.name }}",
+ "modelInvariantId": "{{ service_instance.sdc_service.unique_uuid }}",
+ "modelVersion": "1.0",
+ "modelVersionId": "{{ service_instance.sdc_service.identifier }}"
+ },
+ "requestParameters": {
+ "testApi": "GR_API",
+ "aLaCarte": {{ a_la_carte | tojson }}
+ }{% if service_instance.sdc_service.has_vnfs %},
+ {# the code below is needed to be refactored #}
+ {# https://gitlab.com/Orange-OpenSource/lfn/onap/python-onapsdk/-/issues/133 #}
+ "cloudConfiguration": {
+ "cloudOwner": "{{ service_instance.service_subscription.cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ service_instance.service_subscription.cloud_region.cloud_region_id }}",
+ "tenantId": "{{ service_instance.service_subscription.tenant.tenant_id }}"
+ }{% endif %}
+ }
+} \ No newline at end of file
diff --git a/src/onapsdk/so/templates/deletion_vf_module.json.j2 b/src/onapsdk/so/templates/deletion_vf_module.json.j2
new file mode 100644
index 0000000..8f83717
--- /dev/null
+++ b/src/onapsdk/so/templates/deletion_vf_module.json.j2
@@ -0,0 +1,27 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "source": "VID",
+ "requestorId": "demo"
+ },
+ "modelInfo": {
+ "modelType": "vfModule",
+ "modelInvariantId": "{{ vf_module_instance.model_invariant_id }}",
+ "modelVersionId": "{{ vf_module_instance.model_version_id }}",
+ "modelName": "{{ vf_module_instance.vf_module_name }}",
+ "modelVersion": "{{ vf_module_instance.resource_version }}",
+ "modelCustomizationId": "{{ vf_module_instance.model_customization_id }}"
+ },
+ "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": "{{ vf_module_instance.vnf_instance.service_instance.service_subscription.cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ vf_module_instance.vnf_instance.service_instance.service_subscription.cloud_region.cloud_region_id }}",
+ "tenantId": "{{ vf_module_instance.vnf_instance.service_instance.service_subscription.tenant.tenant_id }}"
+ }
+ }
+} \ No newline at end of file
diff --git a/src/onapsdk/so/templates/deletion_vnf.json.j2 b/src/onapsdk/so/templates/deletion_vnf.json.j2
new file mode 100644
index 0000000..fb640ec
--- /dev/null
+++ b/src/onapsdk/so/templates/deletion_vnf.json.j2
@@ -0,0 +1,28 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "source": "VID",
+ "requestorId": "demo"
+ },
+ "modelInfo": {
+ "modelType": "vnf",
+ "modelName": "{{ vnf_instance.vnf.model_name }}",
+ "modelInvariantId": "{{ vnf_instance.vnf.model_invariant_id }}",
+ "modelVersion": "{{ vnf_instance.vnf.model_version }}",
+ "modelVersionId": "{{ vnf_instance.vnf.model_version_id }}",
+ "modelCustomizationId": "{{ vnf_instance.vnf.model_customization_id }}",
+ "modelCustomizationName": "{{ vnf_instance.vnf.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": "{{ vnf_instance.service_instance.service_subscription.cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ vnf_instance.service_instance.service_subscription.cloud_region.cloud_region_id }}",
+ "tenantId": "{{ vnf_instance.service_instance.service_subscription.tenant.tenant_id }}"
+ }
+ }
+} \ No newline at end of file
diff --git a/src/onapsdk/so/templates/instantiate_multi_vnf_service_macro.json.j2 b/src/onapsdk/so/templates/instantiate_multi_vnf_service_macro.json.j2
new file mode 100644
index 0000000..32e1b68
--- /dev/null
+++ b/src/onapsdk/so/templates/instantiate_multi_vnf_service_macro.json.j2
@@ -0,0 +1,121 @@
+{% extends "instantiate_service_macro.json.j2" %}
+
+{% block subscriptionServiceType %}
+ "subscriptionServiceType": "{{ so_service.subscription_service_type }}",
+{% endblock %}
+
+{% block pnfs %}
+ {% if so_service.pnfs %}
+ "pnfs": [
+ {% for pnf in so_service.pnfs %}
+ {
+ "modelInfo":{
+ {% for sdc_pnf in sdc_service.pnfs %}
+ {% if sdc_pnf.model_name == pnf.model_name %}
+ "modelCustomizationName":"{{ sdc_pnf.name }}",
+ "modelCustomizationId":"{{ sdc_pnf.model_customization_id }}",
+ "modelInvariantId":"{{ sdc_service.unique_uuid }}",
+ "modelVersionId":"{{ sdc_service.identifier }}",
+ "modelName":"{{ sdc_service.name }}",
+ "modelType":"pnf",
+ "modelVersion":"{{ sdc_pnf.model_version }}"
+ {% endif %}
+ {% endfor %}
+ },
+ "platform":{
+ "platformName":"{{ platform }}"
+ },
+ "lineOfBusiness":{
+ "lineOfBusinessName":"{{ line_of_business }}"
+ },
+ "productFamilyId":"{{ aai_service.service_id }}",
+ "instanceParams":[],
+ {% if pnf.processing_priority %}
+ "processingPriority": "{{ pnf.processing_priority }}",
+ {% endif %}
+ "instanceName": "{{ pnf.instance_name }}"
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]{% if so_service.vnfs %},{% endif %}
+ {% endif %}
+{% endblock %}
+
+{% block vnfs %}
+ {% if so_service.vnfs %}
+ "vnfs": [
+ {% for vnf in so_service.vnfs %}
+ {
+ "modelInfo": {
+ {% for sdc_vnf in sdc_service.vnfs %}
+ {% if sdc_vnf.model_name == vnf.model_name %}
+ "modelName": "{{ sdc_vnf.model_name }}",
+ "modelVersionId": "{{ sdc_vnf.model_version_id }}",
+ "modelInvariantUuid": "{{ sdc_vnf.model_invariant_uuid }}",
+ "modelVersion": "{{ sdc_vnf.model_version }}",
+ "modelCustomizationId": "{{ sdc_vnf.model_customization_id }}",
+ "modelInstanceName": "{{ sdc_vnf.model_name }}"
+ {% endif %}
+ {% endfor %}
+ },
+ "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": "{{ vnf.instance_name }}",
+ "instanceParams": [
+ {
+ {% for key, value in vnf.parameters.items() %}
+ "{{ key }}": "{{ value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ }
+ ],
+ {% if vnf.processing_priority %}
+ "processingPriority": "{{ vnf.processing_priority }}",
+ {% endif %}
+ "vfModules": [
+ {% for vf_module in vnf.vf_modules %}
+ {
+ "modelInfo": {
+ {% for sdc_vnf in sdc_service.vnfs %}
+ {% if sdc_vnf.model_name == vnf.model_name %}
+ {% for sdc_vf_module in sdc_vnf.vf_modules %}
+ {% set mylist = sdc_vf_module.name.split('..') %}
+ {% set item = mylist|length-2 %}
+ {% if vf_module.model_name == mylist[item] %}
+ "modelName": "{{ sdc_vf_module.model_name }}",
+ "modelVersionId": "{{ sdc_vf_module.model_version_id }}",
+ "modelInvariantUuid": "{{ sdc_vf_module.model_invariant_uuid }}",
+ "modelVersion": "{{ sdc_vf_module.model_version }}",
+ "modelCustomizationId": "{{ sdc_vf_module.model_customization_id }}"
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+ },
+ "instanceName": "{{ vf_module.instance_name }}",
+ {% if vf_module.processing_priority %}
+ "processingPriority": "{{ vf_module.processing_priority }}",
+ {% endif %}
+ "instanceParams": [
+ {
+ {% for key, value in vf_module.parameters.items() %}
+ "{{ key }}": "{{ value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ }
+ ]
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]
+ {% endif %}
+{% endblock %}
diff --git a/src/onapsdk/so/templates/instantiate_network_ala_carte.json.j2 b/src/onapsdk/so/templates/instantiate_network_ala_carte.json.j2
new file mode 100644
index 0000000..90b3c16
--- /dev/null
+++ b/src/onapsdk/so/templates/instantiate_network_ala_carte.json.j2
@@ -0,0 +1,10 @@
+{% extends "instantiate_network_vnf_ala_carte_base.json.j2" %}
+{% block model_info %}
+ "modelType": "network",
+ "modelInvariantId": "{{ network.model_invariant_id }}",
+ "modelVersionId": "{{ network.model_version_id }}",
+ "modelName": "{{ network.model_name }}",
+ "modelVersion": "{{ network.model_version }}",
+ "modelCustomizationId": "{{ network.model_customization_id }}",
+ "modelCustomizationName": "{{ network.name }}"
+{% endblock %} \ No newline at end of file
diff --git a/src/onapsdk/so/templates/instantiate_network_vnf_ala_carte_base.json.j2 b/src/onapsdk/so/templates/instantiate_network_vnf_ala_carte_base.json.j2
new file mode 100644
index 0000000..757cdd8
--- /dev/null
+++ b/src/onapsdk/so/templates/instantiate_network_vnf_ala_carte_base.json.j2
@@ -0,0 +1,44 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "instanceName": "{{ instance_name }}",
+ "source": "VID",
+ "suppressRollback": false,
+ "requestorId": "test",
+ "productFamilyId": "{{ service_instance.model_invariant_id }}"
+ },
+ "modelInfo": {
+ {% block model_info %}{% endblock %}
+ },
+ "requestParameters": {
+ "userParams": [
+ {% block user_params %}{% endblock %}
+ ],
+ "aLaCarte": true,
+ "testApi": "GR_API"
+ },
+ "cloudConfiguration": {
+ "tenantId": "{{ tenant.tenant_id }}",
+ "cloudOwner": "{{ cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ cloud_region.cloud_region_id }}"
+ },
+ "lineOfBusiness": {
+ "lineOfBusinessName": "{{ line_of_business }}"
+ },
+ "platform": {
+ "platformName": "{{ platform }}"
+ },
+ "relatedInstanceList": [{
+ "relatedInstance": {
+ "instanceId": "{{ service_instance.instance_id }}",
+ "modelInfo": {
+ "modelType": "service",
+ "modelName": "{{ service.name }}",
+ "modelInvariantId": "{{ service.unique_uuid }}",
+ "modelVersion": "1.0",
+ "modelVersionId": "{{ service.identifier }}"
+ }
+ }
+ }]
+ }
+} \ No newline at end of file
diff --git a/src/onapsdk/so/templates/instantiate_service_ala_carte.json.j2 b/src/onapsdk/so/templates/instantiate_service_ala_carte.json.j2
new file mode 100644
index 0000000..4954cde
--- /dev/null
+++ b/src/onapsdk/so/templates/instantiate_service_ala_carte.json.j2
@@ -0,0 +1,45 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "instanceName": "{{ service_instance_name }}",
+ "source": "VID",
+ "suppressRollback": false,
+ "requestorId": "demo"
+ },
+ "modelInfo": {
+ "modelType": "service",
+ "modelInvariantId": "{{ sdc_service.unique_uuid }}",
+ "modelVersionId": "{{ sdc_service.identifier }}",
+ "modelName": "{{ sdc_service.name }}",
+ "modelVersion": "1.0"
+ },
+ "cloudConfiguration": {
+ "tenantId": "{{ tenant.tenant_id }}",
+ "cloudOwner": "{{ cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ cloud_region.cloud_region_id }}"
+ },
+ "requestParameters": {
+ "userParams": [
+ {% if enable_multicloud %}
+ {
+ "name":"orchestrator",
+ "value":"multicloud"
+ }
+ {% endif %}
+ ],
+ "testApi": "GR_API",
+ "subscriptionServiceType": "{{ service_subscription.service_type }}",
+ "aLaCarte": true
+ },
+ "subscriberInfo": {
+ "globalSubscriberId": "{{ customer.global_customer_id }}"
+ },
+ "project": {
+ "projectName": "{{ project }}"
+ },
+ "owningEntity": {
+ "owningEntityId": "{{ owning_entity.owning_entity_id }}",
+ "owningEntityName": "{{ owning_entity.name }}"
+ }
+ }
+} \ No newline at end of file
diff --git a/src/onapsdk/so/templates/instantiate_service_macro.json.j2 b/src/onapsdk/so/templates/instantiate_service_macro.json.j2
new file mode 100644
index 0000000..43b92ee
--- /dev/null
+++ b/src/onapsdk/so/templates/instantiate_service_macro.json.j2
@@ -0,0 +1,173 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "suppressRollback": false,
+ {% if aai_service %}
+ "productFamilyId":"{{ aai_service.service_id }}",
+ {% else %}
+ "productFamilyId": "1234",
+ {% endif %}
+ "requestorId": "demo",
+ "instanceName": "{{ service_instance_name }}",
+ "source": "VID"
+ },
+ "modelInfo": {
+ "modelType": "service",
+ "modelInvariantId": "{{ sdc_service.unique_uuid }}",
+ "modelVersionId": "{{ sdc_service.identifier }}",
+ "modelName": "{{ sdc_service.name }}",
+ "modelVersion": "1.0"
+ },
+ {% if sdc_service.has_vnfs %}
+ "cloudConfiguration": {
+ "tenantId": "{{ tenant.tenant_id }}",
+ "cloudOwner": "{{ cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ cloud_region.cloud_region_id }}"
+ },
+ {% endif %}
+ "subscriberInfo": {
+ "globalSubscriberId": "{{ customer.global_customer_id }}"
+ },
+ "requestParameters": {
+ {% block subscriptionServiceType %}
+ "subscriptionServiceType": "{{ service_subscription.service_type }}",
+ {% endblock %}
+ "userParams": [
+ {
+ "Homing_Solution": "none"
+ },
+ {% if enable_multicloud %}
+ {
+ "name":"orchestrator",
+ "value":"multicloud"
+ },
+ {% endif %}
+ {
+ "service": {
+ "instanceParams": [],
+ "instanceName": "{{ service_instance_name }}",
+ "resources": {
+ {% block pnfs %}
+ {% if sdc_service.pnfs %}
+ "pnfs":[
+ {% for pnf in sdc_service.pnfs %}
+ {
+ "modelInfo":{
+ "modelCustomizationName":"{{ pnf.name }}",
+ "modelCustomizationId":"{{ pnf.model_customization_id }}",
+ "modelInvariantId":"{{ sdc_service.unique_uuid }}",
+ "modelVersionId":"{{ sdc_service.identifier }}",
+ "modelName":"{{ sdc_service.name }}",
+ "modelType":"pnf",
+ "modelVersion":"1.0"
+ },
+ "platform":{
+ "platformName":"{{ platform }}"
+ },
+ "lineOfBusiness":{
+ "lineOfBusinessName":"{{ line_of_business }}"
+ },
+ "productFamilyId":"{{ aai_service.service_id }}",
+ "instanceParams":[],
+ "instanceName":"{{ service_instance_name }}"
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]
+ {% if sdc_service.vnfs %},{% endif %}
+ {% endif %}
+ {% endblock %}
+ {% block vnfs %}
+ {% if sdc_service.vnfs %}
+ "vnfs": [
+ {% for vnf in sdc_service.vnfs %}
+ {
+ "modelInfo": {
+ "modelName": "{{ vnf.model_name }}",
+ "modelVersionId": "{{ vnf.model_version_id }}",
+ "modelInvariantUuid": "{{ vnf.model_invariant_id }}",
+ "modelVersion": "{{ vnf.model_version }}",
+ "modelCustomizationId": "{{ vnf.model_customization_id }}",
+ "modelInstanceName": "{{ vnf.model_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": "{{ vnf.model_name }}",
+ "instanceParams": [
+ {
+ {% for vnf_parameter in vnf_parameters %}
+ {% if vnf_parameter.name == vnf.model_name %}
+ {% for parameter in vnf_parameter.vnf_parameters %}
+ "{{ parameter.name }}": "{{ parameter.value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+ }
+ ],
+ "vfModules": [
+ {% for vf_module in vnf.vf_modules %}
+ {
+ "modelInfo": {
+ "modelName": "{{ vf_module.model_name }}",
+ "modelVersionId": "{{ vf_module.model_version_id }}",
+ "modelInvariantUuid": "{{ vf_module.model_invariant_uuid }}",
+ "modelVersion": "{{ vf_module.model_version }}",
+ "modelCustomizationId": "{{ vf_module.model_customization_id }}"
+ },
+ "instanceName": "{{ service_instance_name }}_{{ vf_module.name }}",
+ "instanceParams": [
+ {
+ {% for vnf_parameter in vnf_parameters %}
+ {% if vnf_parameter.name == vnf.model_name %}
+ {% set mylist = vf_module.name.split('..') %}
+ {% set item = mylist|length-2 %}
+ {% for vf_module_parameter in vnf_parameter.vfmodule_parameters %}
+ {% if vf_module_parameter.name == mylist[item] %}
+ {% for parameter in vf_module_parameter.vfmodule_parameters %}
+ "{{ parameter.name }}": "{{ parameter.value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+ }
+ ]
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]
+ {% endif %}
+ {% endblock %}
+ },
+ "modelInfo": {
+ "modelVersion": "1.0",
+ "modelVersionId": "{{ sdc_service.identifier }}",
+ "modelInvariantId": "{{ sdc_service.unique_uuid }}",
+ "modelName": "{{ sdc_service.name }}",
+ "modelType": "service"
+ }
+ }
+ }
+ ],
+ "aLaCarte": false
+ },
+ "project": {
+ "projectName": "{{ project }}"
+ },
+ "owningEntity": {
+ "owningEntityId": "{{ owning_entity.owning_entity_id }}",
+ "owningEntityName": "{{ owning_entity.name }}"
+ }
+ }
+}
diff --git a/src/onapsdk/so/templates/instantiate_vf_module_ala_carte.json.j2 b/src/onapsdk/so/templates/instantiate_vf_module_ala_carte.json.j2
new file mode 100644
index 0000000..0738379
--- /dev/null
+++ b/src/onapsdk/so/templates/instantiate_vf_module_ala_carte.json.j2
@@ -0,0 +1,66 @@
+{
+ "requestDetails": {
+ "requestInfo":
+ {
+ "instanceName": "{{ vf_module_instance_name }}",
+ "source": "VID",
+ "suppressRollback": false,
+ "requestorId": "test"
+ },
+ "modelInfo": {
+ "modelType": "vfModule",
+ "modelInvariantId": "{{ vf_module.model_invariant_uuid }}",
+ "modelVersionId": "{{ vf_module.model_version_id }}",
+ "modelName": "{{ vf_module.model_name }}",
+ "modelVersion": "{{ vf_module.model_version }}",
+ "modelCustomizationId": "{{ vf_module.model_customization_id }}",
+ "modelCustomizationName": "{{ vf_module.model_name }}"
+ },
+ "requestParameters": {
+ "userParams": [
+ {% for parameter in vf_module_parameters %}
+ {
+ "name": "{{ parameter.name }}",
+ "value": "{{ parameter.value }}"
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ],
+ "testApi": "GR_API",
+ "usePreload": true,
+ "aLaCarte": true
+ },
+ "cloudConfiguration": {
+ "tenantId": "{{ tenant.tenant_id }}",
+ "cloudOwner": "{{ cloud_region.cloud_owner }}",
+ "lcpCloudRegionId": "{{ cloud_region.cloud_region_id }}"
+ },
+ "relatedInstanceList": [
+ {
+ "relatedInstance": {
+ "instanceId": "{{ vnf_instance.service_instance.instance_id }}",
+ "modelInfo": {
+ "modelType": "service",
+ "modelName": "{{ service.name }}",
+ "modelInvariantId": "{{ service.unique_uuid }}",
+ "modelVersion": "1.0",
+ "modelVersionId": "{{ service.identifier }}"
+ }
+ }
+ },
+ {
+ "relatedInstance": {
+ "instanceId": "{{ vnf_instance.vnf_id }}",
+ "modelInfo": {
+ "modelType": "vnf",
+ "modelName": "{{ vnf_instance.vnf.model_name }}",
+ "modelInvariantId": "{{ vnf_instance.vnf.model_invariant_id }}",
+ "modelVersion": "{{ vnf_instance.vnf.model_version }}",
+ "modelVersionId": "{{ vnf_instance.vnf.model_version_id }}",
+ "modelCustomizationId": "{{ vnf_instance.vnf.model_customization_id }}",
+ "modelCustomizationName": "{{ vnf_instance.vnf.name }}"
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/src/onapsdk/so/templates/instantiate_vnf_ala_carte.json.j2 b/src/onapsdk/so/templates/instantiate_vnf_ala_carte.json.j2
new file mode 100644
index 0000000..9fbf989
--- /dev/null
+++ b/src/onapsdk/so/templates/instantiate_vnf_ala_carte.json.j2
@@ -0,0 +1,18 @@
+{% extends "instantiate_network_vnf_ala_carte_base.json.j2" %}
+{% block model_info %}
+ "modelType": "vnf",
+ "modelInvariantId": "{{ vnf.model_invariant_id }}",
+ "modelVersionId": "{{ vnf.model_version_id }}",
+ "modelName": "{{ vnf.model_name }}",
+ "modelVersion": "{{ vnf.model_version }}",
+ "modelCustomizationId": "{{ vnf.model_customization_id }}",
+ "modelCustomizationName": "{{ vnf.name }}"
+{% endblock %}
+{% block user_params %}
+{% for parameter in vnf_parameters %}
+{
+ "name": "{{ parameter.name }}",
+ "value": "{{ parameter.value }}"
+}{% if not loop.last %},{% endif %}
+{% endfor %}
+{% endblock %} \ No newline at end of file
diff --git a/src/onapsdk/so/templates/instantiate_vnf_macro.json.j2 b/src/onapsdk/so/templates/instantiate_vnf_macro.json.j2
new file mode 100644
index 0000000..2d7aeee
--- /dev/null
+++ b/src/onapsdk/so/templates/instantiate_vnf_macro.json.j2
@@ -0,0 +1,153 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "instanceName": "{{ service_instance.instance_name }}",
+ "source": "VID",
+ "suppressRollback": false,
+ "requestorId": "demo",
+ "productFamilyId": "1234"
+ },
+ "modelInfo": {
+ "modelType": "vnf",
+ "modelInvariantId": "{{ vnf.model_invariant_id }}",
+ "modelVersionId": "{{ vnf.model_version_id }}",
+ "modelName": "{{ vnf.model_name }}",
+ "modelVersion": "{{ vnf.model_version }}",
+ "modelCustomizationId": "{{ vnf.model_customization_id }}",
+ "modelInstanceName": "{{ vnf.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 vnfs %}
+ "vnfs": [
+ {
+ "modelInfo": {
+ "modelName": "{{ vnf.model_name }}",
+ "modelVersionId": "{{ vnf.model_version_id }}",
+ "modelInvariantUuid": "{{ vnf.model_invariant_id }}",
+ "modelVersion": "{{ vnf.model_version }}",
+ "modelCustomizationId": "{{ vnf.model_customization_id }}",
+ "modelInstanceName": "{{ vnf.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 vnf_parameter in vnf_parameters %}
+ {% if vnf_parameter.name == vnf.model_name %}
+ {% for parameter in vnf_parameter.vnf_parameters %}
+ "{{ parameter.name }}": "{{ parameter.value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+ }
+ ],
+ "vfModules": [
+ {% for vf_module in vnf.vf_modules %}
+
+ {
+ "modelInfo": {
+ "modelName": "{{ vf_module.model_name }}",
+ "modelVersionId": "{{ vf_module.model_version_id }}",
+ "modelInvariantUuid": "{{ vf_module.model_invariant_uuid }}",
+ "modelVersion": "{{ vf_module.model_version }}",
+ "modelCustomizationId": "{{ vf_module.model_customization_id }}"
+ },
+ "instanceName": "{{instance_name}}_{{ vf_module.name }}",
+ "instanceParams": [
+ {
+ {% for vnf_parameter in vnf_parameters %}
+ {% if vnf_parameter.name == vnf.model_name %}
+ {% set mylist = vf_module.name.split('..') %}
+ {% set item = mylist|length-2 %}
+ {% for vf_module_parameter in vnf_parameter.vfmodule_parameters %}
+ {% if vf_module_parameter.name == mylist[item] %}
+ {% for parameter in vf_module_parameter.vfmodule_parameters %}
+ "{{ parameter.name }}": "{{ parameter.value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+ }
+ ]
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]
+ }
+ ]
+ {% endblock %}
+ },
+ "modelInfo": {
+ "modelType": "vnf",
+ "modelInvariantId": "{{ vnf.model_invariant_id }}",
+ "modelVersionId": "{{ vnf.model_version_id }}",
+ "modelName": "{{ vnf.model_name }}",
+ "modelVersion": "{{ vnf.model_version }}",
+ "modelCustomizationId": "{{ vnf.model_customization_id }}",
+ "modelCustomizationName": "{{ vnf.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_vnf_macro_so_vnf.json.j2 b/src/onapsdk/so/templates/instantiate_vnf_macro_so_vnf.json.j2
new file mode 100644
index 0000000..c7f4356
--- /dev/null
+++ b/src/onapsdk/so/templates/instantiate_vnf_macro_so_vnf.json.j2
@@ -0,0 +1,151 @@
+{
+ "requestDetails": {
+ "requestInfo": {
+ "instanceName": "{{ service_instance.instance_name }}",
+ "source": "VID",
+ "suppressRollback": false,
+ "requestorId": "demo",
+ "productFamilyId": "1234"
+ },
+ "modelInfo": {
+ "modelType": "vnf",
+ "modelInvariantId": "{{ vnf.model_invariant_id }}",
+ "modelVersionId": "{{ vnf.model_version_id }}",
+ "modelName": "{{ vnf.model_name }}",
+ "modelVersion": "{{ vnf.model_version }}",
+ "modelCustomizationId": "{{ vnf.model_customization_id }}",
+ "modelInstanceName": "{{ vnf.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 vnfs %}
+ "vnfs": [
+ {
+ "modelInfo": {
+ "modelName": "{{ vnf.model_name }}",
+ "modelVersionId": "{{ vnf.model_version_id }}",
+ "modelInvariantUuid": "{{ vnf.model_invariant_id }}",
+ "modelVersion": "{{ vnf.model_version }}",
+ "modelCustomizationId": "{{ vnf.model_customization_id }}",
+ "modelInstanceName": "{{ vnf.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_vnf.parameters.items() %}
+ "{{ key }}": "{{ value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ }
+ ],
+ "vfModules": [
+ {% for vf_module in so_vnf.vf_modules %}
+ {
+ "modelInfo": {
+
+ {% if vnf.model_name == so_vnf.model_name %}
+ {% for sdc_vf_module in vnf.vf_modules %}
+ {% set mylist = sdc_vf_module.name.split('..') %}
+ {% set item = mylist|length-2 %}
+ {% if vf_module.model_name == mylist[item] %}
+ "modelName": "{{ sdc_vf_module.model_name }}",
+ "modelVersionId": "{{ sdc_vf_module.model_version_id}}",
+ "modelInvariantUuid": "{{ sdc_vf_module.model_invariant_uuid }}",
+ "modelVersion": "{{ sdc_vf_module.model_version }}",
+ "modelCustomizationId": "{{ sdc_vf_module.model_customization_id }}"
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+
+ },
+ "instanceName": "{{ vf_module.instance_name }}",
+ {% if vf_module.processing_priority %}
+ "processingPriority": "{{ vf_module.processing_priority }}",
+ {% endif %}
+ "instanceParams": [
+ {
+ {% for key, value in vf_module.parameters.items() %}
+ "{{ key }}": "{{ value }}"{% if not loop.last %},{% endif %}
+ {% endfor %}
+ }
+ ]
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]
+ }
+ ]
+ {% endblock %}
+ },
+ "modelInfo": {
+ "modelType": "vnf",
+ "modelInvariantId": "{{ vnf.model_invariant_id }}",
+ "modelVersionId": "{{ vnf.model_version_id }}",
+ "modelName": "{{ vnf.model_name }}",
+ "modelVersion": "{{ vnf.model_version }}",
+ "modelCustomizationId": "{{ vnf.model_customization_id }}",
+ "modelCustomizationName": "{{ vnf.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/service_instance_model_info.json.j2 b/src/onapsdk/so/templates/service_instance_model_info.json.j2
new file mode 100644
index 0000000..fc66de4
--- /dev/null
+++ b/src/onapsdk/so/templates/service_instance_model_info.json.j2
@@ -0,0 +1,7 @@
+{
+ "modelType": "service",
+ "modelInvariantId": "{{ model_invariant_id }}",
+ "modelName": "{{ model_name }}",
+ "modelVersion": "{{ model_version }}",
+ "modelVersionId": "{{ model_name_version_id }}"
+}
diff --git a/src/onapsdk/so/templates/vf_model_info.json.j2 b/src/onapsdk/so/templates/vf_model_info.json.j2
new file mode 100644
index 0000000..4b40898
--- /dev/null
+++ b/src/onapsdk/so/templates/vf_model_info.json.j2
@@ -0,0 +1,15 @@
+[
+{% for _, module in modules.items() %}
+ {
+ "modelInfo": {
+ "modelName": "{{ module["metadata"]["vfModuleModelName"] }}",
+ "modelVersion": "{{ module.metadata.vfModuleModelVersion }}",
+ "modelVersionId": "{{ module.metadata.vfModuleModelUUID }}",
+ "modelInvariantUuid": "{{ module.metadata.vfModuleInvariantUUID }}",
+ "modelCustomizationId": "{{ module.metadata.vfModuleModelCustomizationUUID }}"
+ },
+ "instanceName": "{{ module.metadata.vfModuleModelName }}",
+ "instanceParams": []
+ }{% if not loop.last %},{% endif %}
+{% endfor %}
+] \ No newline at end of file
diff --git a/src/onapsdk/so/templates/vnf_model_info.json.j2 b/src/onapsdk/so/templates/vnf_model_info.json.j2
new file mode 100644
index 0000000..ecc788b
--- /dev/null
+++ b/src/onapsdk/so/templates/vnf_model_info.json.j2
@@ -0,0 +1,9 @@
+{
+ "modelType": "vnf",
+ "modelName": "{{ vnf_model_name }}",
+ "modelVersion": "{{ vnf_model_version }}",
+ "modelVersionId": "{{ vnf_model_version_id }}",
+ "modelInvariantUuid": "{{ vnf_model_invariant_uuid }}",
+ "modelCustomizationId": "{{ vnf_model_customization_id }}",
+ "modelInstanceName": "{{ vnf_model_instance_name }}"
+}