OSMENG-1048 Implement day1 configuration for VDU
Day1 config implementation, arranging existing unit tests and imports
adding task and execution timeout policy for workflows in tests.
Change-Id: Ie5a2626eec01176723d8130576facbf4934d5285
Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>
diff --git a/osm_lcm/temporal/vnf_activities.py b/osm_lcm/temporal/vnf_activities.py
index 2e8ab1c..9581db0 100644
--- a/osm_lcm/temporal/vnf_activities.py
+++ b/osm_lcm/temporal/vnf_activities.py
@@ -14,12 +14,15 @@
# limitations under the License.
import logging
+from typing import List, Any
+
from osm_common.temporal_constants import (
ACTIVITY_CHANGE_VNF_STATE,
ACTIVITY_CHANGE_VNF_INSTANTIATION_STATE,
ACTIVITY_GET_TASK_QUEUE,
ACTIVITY_GET_VIM_CLOUD,
- ACTIVITY_GET_VNF_DETAILS,
+ ACTIVITY_GET_VNF_DESCRIPTOR,
+ ACTIVITY_GET_VNF_RECORD,
ACTIVITY_SEND_NOTIFICATION_FOR_VNF,
ACTIVITY_SET_VNF_MODEL,
VIM_TYPE_TASK_QUEUE_MAPPINGS,
@@ -31,14 +34,20 @@
GetTaskQueueOutput,
GetVimCloudInput,
GetVimCloudOutput,
- GetVnfDetailsInput,
- GetVnfDetailsOutput,
- VnfInstantiateInput,
+ GetVnfDescriptorInput,
+ GetVnfDescriptorOutput,
+ GetVnfRecordInput,
+ GetVnfRecordOutput,
+ SetVnfModelInput,
+ VduComputeConstraints,
)
from osm_lcm.data_utils.database.database import Database
from temporalio import activity
+CONFIG_IDENTIFIER = "config::"
+
+
class VnfOperations:
def __init__(self, db: Database):
self.db: Database = db
@@ -81,7 +90,7 @@
"""Finds the cloud by checking the VIM account of VNF.
Collaborators:
- DB Access Object
+ DB Read: vnfrs, vim_accounts
Raises (retryable):
DbException: If DB read operations fail, the collection or DB record ID does not exist.
@@ -104,14 +113,14 @@
self.logger.debug(f"Got the cloud type {cloud} for VNF operations.")
return GetVimCloudOutput(cloud=cloud)
- @activity.defn(name=ACTIVITY_GET_VNF_DETAILS)
- async def get_vnf_details(
- self, get_vnf_details_input: GetVnfDetailsInput
- ) -> GetVnfDetailsOutput:
+ @activity.defn(name=ACTIVITY_GET_VNF_RECORD)
+ async def get_vnf_record(
+ self, get_vnf_record_input: GetVnfRecordInput
+ ) -> GetVnfRecordOutput:
"""Gets the VNF record and VNF descriptor from Database.
Collaborators:
- DB read: vnfrs, vnfds
+ DB read: vnfrs
Raises (retryable):
DbException: If DB read operations fail, the collection or DB record ID does not exist.
@@ -126,10 +135,93 @@
This is an idempotent activity.
"""
- vnfr = self.db.get_one("vnfrs", {"_id": get_vnf_details_input.vnfr_uuid})
- vnfd = self.db.get_one("vnfds", {"_id": vnfr["vnfd-id"]})
+ vnfr = self.db.get_one("vnfrs", {"_id": get_vnf_record_input.vnfr_uuid})
+ self.logger.debug("Got the vnfr from Database for VNF operations.")
+ return GetVnfRecordOutput(vnfr=vnfr)
+
+ @activity.defn(name=ACTIVITY_GET_VNF_DESCRIPTOR)
+ async def get_vnf_descriptor(
+ self, get_vnf_descriptor_input: GetVnfDescriptorInput
+ ) -> GetVnfDescriptorOutput:
+ """Gets the VNF record and VNF descriptor from Database.
+
+ Collaborators:
+ DB read: vnfds
+
+ Raises (retryable):
+ DbException: If DB read operations fail, the collection or DB record ID does not exist.
+
+ Activity Lifecycle:
+ This activity should complete relatively quickly (less than 10
+ second).
+
+ This activity will not report a heartbeat due to its
+ short-running nature.
+
+ This is an idempotent activity.
+
+ """
+ vnfd = self.db.get_one("vnfds", {"_id": get_vnf_descriptor_input.vnfd_uuid})
self.logger.debug("Got the vnfr and vnfd from Database for VNF operations.")
- return GetVnfDetailsOutput(vnfr=vnfr, vnfd=vnfd)
+ return GetVnfDescriptorOutput(vnfd=vnfd)
+
+ @staticmethod
+ def get_vdu_instantiation_params(
+ vdu_id: str, vnf_instantiation_config: dict
+ ) -> dict:
+ for vdu in vnf_instantiation_config.get("vdu", []):
+ if vdu.get("id") == vdu_id:
+ return vdu.get("configurable-properties", {})
+ return {}
+
+ @staticmethod
+ def get_compute_constraints(vdu: dict, vnfd: dict) -> VduComputeConstraints:
+ compute_desc_id = vdu.get("virtual-compute-desc")
+ if not compute_desc_id:
+ return VduComputeConstraints(cores=0, mem=0)
+ flavor_details = VnfOperations._get_flavor_details(compute_desc_id, vnfd)
+ if not flavor_details:
+ return VduComputeConstraints(cores=0, mem=0)
+
+ cpu_cores = flavor_details.get("virtual-cpu", {}).get("num-virtual-cpu", 0)
+ memory_gb = flavor_details.get("virtual-memory", {}).get("size", 0)
+ return VduComputeConstraints(cores=cpu_cores, mem=int(memory_gb))
+
+ @staticmethod
+ def _get_flavor_details(compute_desc_id: str, vnfd: dict) -> Any:
+ for flavor in vnfd.get("virtual-compute-desc", []):
+ if flavor.get("id") == compute_desc_id:
+ return flavor
+ return None
+
+ @staticmethod
+ def get_application_config(vdu: dict, vdu_instantiation_config: dict) -> dict:
+ configurable_properties = vdu.get("configurable-properties", [])
+
+ config_from_descriptor = VnfOperations._get_only_config_items(
+ VnfOperations._list_to_dict(configurable_properties)
+ )
+
+ config_from_instantiation = VnfOperations._get_only_config_items(
+ vdu_instantiation_config
+ )
+ return {**config_from_descriptor, **config_from_instantiation}
+
+ @staticmethod
+ def _get_only_config_items(config: dict) -> dict:
+ return {
+ key[len(CONFIG_IDENTIFIER) :]: value
+ for key, value in config.items()
+ if key.startswith(CONFIG_IDENTIFIER)
+ }
+
+ @staticmethod
+ def _list_to_dict(indata: List[dict]) -> dict:
+ return {
+ item["key"]: item["value"]
+ for item in indata
+ if item.get("key") and item.get("value")
+ }
class VnfDbActivity:
@@ -208,7 +300,7 @@
)
@activity.defn(name=ACTIVITY_SET_VNF_MODEL)
- async def set_vnf_model(self, set_vnf_model_input: VnfInstantiateInput) -> None:
+ async def set_vnf_model(self, set_vnf_model_input: SetVnfModelInput) -> None:
"""Updates the model name of VNF in VNFR.
Collaborators: