OSMENG-1155 Implementation of Constants and Dataclasses 55/13555/16
authorDario Faccin <dario.faccin@canonical.com>
Tue, 20 Jun 2023 14:12:29 +0000 (16:12 +0200)
committerDario Faccin <dario.faccin@canonical.com>
Wed, 28 Jun 2023 07:43:48 +0000 (09:43 +0200)
Add stubs for common elements, workflows and activities

Change-Id: If7a2aa8a6e6627df5293154bf48da742dea57e1c
Signed-off-by: Dario Faccin <dario.faccin@canonical.com>
17 files changed:
osm_common/dataclasses/temporal_dataclasses.py [deleted file]
osm_common/temporal/activities/base.py [new file with mode: 0644]
osm_common/temporal/activities/lcm.py [new file with mode: 0644]
osm_common/temporal/activities/ns.py [new file with mode: 0644]
osm_common/temporal/activities/paas.py [new file with mode: 0644]
osm_common/temporal/activities/vim.py [new file with mode: 0644]
osm_common/temporal/activities/vnf.py [new file with mode: 0644]
osm_common/temporal/dataclasses_common.py [new file with mode: 0644]
osm_common/temporal/states.py [new file with mode: 0644]
osm_common/temporal/workflows/base.py [new file with mode: 0644]
osm_common/temporal/workflows/lcm.py [new file with mode: 0644]
osm_common/temporal/workflows/ns.py [new file with mode: 0644]
osm_common/temporal/workflows/vdu.py [new file with mode: 0644]
osm_common/temporal/workflows/vim.py [new file with mode: 0644]
osm_common/temporal/workflows/vnf.py [new file with mode: 0644]
osm_common/temporal_constants.py [deleted file]
osm_common/temporal_task_queues/task_queues_mappings.py [new file with mode: 0644]

diff --git a/osm_common/dataclasses/temporal_dataclasses.py b/osm_common/dataclasses/temporal_dataclasses.py
deleted file mode 100644 (file)
index 5827ab8..0000000
+++ /dev/null
@@ -1,659 +0,0 @@
-#######################################################################################
-# Copyright ETSI Contributors and Others.
-#
-# 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 dataclasses import dataclass
-from enum import auto, IntEnum
-from typing import List
-
-
-#######################################################################################
-# Defining States
-class VimState(IntEnum):
-    PROCESSING = auto()
-    ENABLED = auto()
-    ERROR = auto()
-
-
-class VimOperationState(IntEnum):
-    COMPLETED = auto()
-    FAILED = auto()
-
-
-class NsState(IntEnum):
-    PROCESSING = auto()
-    INSTANTIATED = auto()
-    ERROR = auto()
-
-
-class VnfLcmOperationState(IntEnum):
-    PROCESSING = auto()
-    COMPLETED = auto()
-    FAILED = auto()
-
-
-class VnfInstantiationState(IntEnum):
-    NOT_INSTANTIATED = auto()
-    INSTANTIATED = auto()
-
-
-class VnfState(IntEnum):
-    STOPPED = auto()
-    STARTED = auto()
-
-
-class LcmOperationState(IntEnum):
-    PROCESSING = auto()
-    COMPLETED = auto()
-    FAILED = auto()
-
-
-#######################################################################################
-# Workflow Dataclasses
-
-
-@dataclass
-class VimOperationInput:
-    """
-    Input dataclass for workflows that perform operations
-    (create, update, delete) on VIMs.
-
-    Attributes:
-    -----------
-    vim_uuid : str
-        The UUID of the VIM account as stored in the OSM vim
-        collection in Mongo
-
-    op_id: str
-        The operation (task) id for this workflow.  This is used
-        by the workflow at the end to update the status of the
-        operation in Mongo vim collection.
-    """
-
-    vim_uuid: str
-    op_id: str
-
-
-@dataclass
-class NsLcmOperationInput:
-    """
-    Input dataclass for workflows that run as LCM operations.
-
-    Attributes:
-    -----------
-
-    nslcmop: dict
-        A dictionary representing the nslcmop record from the
-        database.
-    """
-
-    nslcmop: dict
-
-
-@dataclass
-class CharmInfo:
-    """
-    Input dataclass for
-
-    Attributes:
-    -----------
-    app_name : str
-
-    channel: str
-
-    entity_url: str
-    """
-
-    app_name: str
-    channel: str
-    entity_url: str
-
-
-@dataclass
-class GetVimCloudInput:
-    """
-    Input dataclass for get vim cloud activity.
-
-    Attributes:
-    -----------
-    vnfr_uuid : str
-        The UUID of the VNF which is stored in the OSM vnfrs
-        collection in Mongo.
-
-    """
-
-    vnfr_uuid: str
-
-
-@dataclass
-class GetVimCloudOutput:
-    """
-    Output dataclass for get vim cloud activity.
-
-    Attributes:
-    -----------
-    cloud : str
-        Type of the cloud which is used to Deploy VNF.
-    """
-
-    cloud: str
-
-
-@dataclass
-class VduComputeConstraints:
-    """
-    Input dataclass for VDU constraints
-
-    Attributes:
-    -----------
-    cores : int (Number of virtual CPUs)
-
-    mem: int (GB)
-    """
-
-    cores: int
-    mem: int
-
-
-@dataclass
-class VduInstantiateInput:
-    """
-    Input dataclass for workflow that instantiates a VDU.
-
-    vim_uuid: str
-
-    model_name: str
-
-    charm_info : CharmInfo
-
-    constraints: VduComputeConstraints
-
-    cloud: VIM cloud type
-
-    config: Config details of application
-    """
-
-    vim_uuid: str
-    model_name: str
-    charm_info: CharmInfo
-    constraints: VduComputeConstraints
-    cloud: str
-    config: dict
-
-
-@dataclass
-class VnfInstantiateInput:
-    """
-    Input dataclass for workflow that instantiates a VNF.
-
-    Attributes:
-    -----------
-    vnfr_uuid : str
-        The UUID of the VNF which is stored in the OSM vnfrs
-        collection in Mongo.
-
-    model_name: str
-
-    instantiation_config: dict
-        The instantiation configuration of the VNF
-
-    """
-
-    vnfr_uuid: str
-    model_name: str
-    instantiation_config: dict
-
-
-@dataclass
-class SetVnfModelInput:
-    """
-    Input dataclass for activity that sets the VNF Model.
-
-    Attributes:
-    -----------
-    vnfr_uuid : str
-        The UUID of the VNF which is stored in the OSM vnfrs
-        collection in Mongo.
-
-    model_name: str
-
-    """
-
-    vnfr_uuid: str
-    model_name: str
-
-
-@dataclass
-class VnfPrepareInput:
-    """
-    Input dataclass for workflow that prepare a VNF.
-
-    Attributes:
-    -----------
-    vnfr_uuid : str
-        The UUID of the VNF which is stored in the OSM vnfrs
-        collection in Mongo.
-
-    model_name: str
-
-    """
-
-    vnfr_uuid: str
-    model_name: str
-
-
-@dataclass
-class GetNsRecordInput:
-    """
-    Input dataclass for getting NS record activity.
-
-    Attributes:
-    -----------
-    nsr_uuid :
-        The UUID of the NS record which is stored in the OSM nsrs
-        collection in Mongo.
-
-    """
-
-    nsr_uuid: str
-
-
-@dataclass
-class GetNsRecordOutput:
-    """
-    Output dataclass for getting NS record activity.
-
-    Attributes:
-    -----------
-    nsr : dict
-        NS record retrieved from Database..
-
-    """
-
-    nsr: dict
-
-
-#######################################################################################
-# Activity Dataclasses
-
-
-@dataclass
-class UpdateLcmOperationStateInput:
-    """
-    Input dataclass for updating LCM Operations in the Mongo nslcmops
-    collection.  The following attributes will be updated automatically
-      - statusEnteredTime
-      - _admin.modified
-
-    Attributes:
-    -----------
-    op_id: str
-        The operation (task) id for this activity.  This is the key
-        to the record in nslcmops collection that will be updated.
-
-    op_state : LcmOperationState
-        A representation of the state of the specified operation id,
-        such as PROCESSING, COMPLETED, or FAILED.
-
-    stage: str
-        Human readable checkpoint message, intended only to give the
-        user feedback.
-
-    error_message: str
-        Human readable error message if any failure occurred.
-
-    detailed_status : str
-        Human readable message providing additional details to the
-        operation state, such as the error message explaining why
-        the operation failed.
-    """
-
-    op_id: str
-    op_state: LcmOperationState
-    stage: str
-    error_message: str
-    detailed_status: str
-
-
-@dataclass
-class TestVimConnectivityInput:
-    """
-    Input dataclass for the Test Vim Connectivity Ativity
-
-    Attributes:
-    -----------
-    vim_uuid : str
-        The UUID of the VIM account as stored in the OSM vim
-        collection in Mongo
-    """
-
-    vim_uuid: str
-
-
-@dataclass
-class UpdateVimStateInput:
-    """
-    Input dataclass for updating VIM state in the DB
-
-    Attributes:
-    -----------
-    vim_uuid : str
-        The UUID of the VIM account as stored in the OSM vim
-        collection in Mongo
-
-    operational_state : VimState
-        A representation of the operational state (ENABLED or ERROR)
-        of the VIM.
-
-    message : str
-        Human readable message providing additional details to the
-        operational state, such as the error message associated
-        with the ERROR operational_state.
-    """
-
-    vim_uuid: str
-    operational_state: VimState
-    message: str
-
-
-@dataclass
-class UpdateVimOperationStateInput:
-    """
-    Input dataclass for updating VIM Operations in the Mongo VIM
-    collection.
-
-    Attributes:
-    -----------
-    vim_uuid : str
-        The UUID of the VIM account as stored in the OSM vim
-        collection in Mongo
-
-    op_id: str
-        The operation (task) id for this workflow.  This is used
-        to update the status of the operation in Mongo vim collection.
-
-    op_state : VimOperationState
-        A representation of the state of the specified operation id,
-        such as COMPLETED, or FAILED.
-
-    message : str
-        Human readable message providing additional details to the
-        operation state, such as the error message explaining why
-        the operation failed.
-    """
-
-    vim_uuid: str
-    op_id: str
-    op_state: VimOperationState
-    message: str
-
-
-@dataclass
-class DeleteVimInput:
-    """
-    Input dataclass for deleting vim record from the database
-
-    Attributes:
-    -----------
-    vim_uuid : str
-        The UUID of the VIM account as stored in the OSM vim
-        collection in Mongo
-
-    """
-
-    vim_uuid: str
-
-
-@dataclass
-class DeployNsInput:
-    """
-    Input dataclass for
-
-    Attributes:
-    -----------
-    ns_uuid : str
-        The UUID of the NS as stored in the OSM nsr
-        collection in Mongo
-    """
-
-    ns_uuid: str
-
-
-@dataclass
-class UpdateNsStateInput:
-    """
-    Input dataclass for updating NS state in the DB
-
-    Attributes:
-    -----------
-    ns_uuid : str
-        The UUID of the NS as stored in the OSM ns
-        collection in Mongo
-
-    operational_state : NsState
-        A representation of the operational state (ENABLED or ERROR)
-        of the NS.
-
-    message : str
-        Human readable message providing additional details to the
-        operational state, such as the error message associated
-        with the ERROR operational_state.
-    """
-
-    ns_uuid: str
-    state: NsState
-    message: str
-
-
-@dataclass
-class ModelInfo:
-    """
-    Contains the information related to a model.
-
-    Attributes:
-    -----------
-    vim_uuid : str
-        The UUID of the VIM as stored in the OSM vim_accounts
-        collection in Mongo.
-
-    model_name : str
-        Name of the Juju model used to deploy charms.
-    """
-
-    vim_uuid: str
-    model_name: str
-
-
-@dataclass
-class CheckCharmStatusInput:
-    """
-    Input dataclass for checking on a specific charm's deployment
-    status
-
-    Attributes:
-    -----------
-    vim_uuid : str
-        The UUID of the VIM as stored in the OSM vim_accounts
-        collection in Mongo.
-
-    model_name : str
-        Name of the model to create in Juju.
-
-    application_name : str
-        Name of the application that the state is going to be
-        awaited.
-
-    poll_interval : int (optional)
-        Time, in seconds, to wait between status checks.
-    """
-
-    vim_uuid: str
-    model_name: str
-    application_name: str
-    poll_interval: int = 1
-
-
-@dataclass
-class ChangeVnfStateInput:
-    """
-    Input dataclass for changing VNF State.
-
-    Attributes:
-    -----------
-    vnfr_uuid : str
-        The UUID of the VNF which is stored in the OSM vnfrs
-        collection in Mongo.
-
-    state : VnfState
-        A representation of the VNF state (STOPPED or STARTED).
-    """
-
-    vnfr_uuid: str
-    state: VnfState
-
-
-@dataclass
-class ChangeVnfInstantiationStateInput:
-    """
-    Input dataclass for changing VNF Instantiation State.
-
-    Attributes:
-    -----------
-    vnfr_uuid : str
-        The UUID of the VNF which is stored in the OSM vnfrs
-        collection in Mongo.
-
-    state : VnfInstantiationState
-        A representation of the VNF instantiation state (NOT_INSTANTIATED or INSTANTIATED).
-
-    """
-
-    vnfr_uuid: str
-    state: VnfInstantiationState
-
-
-@dataclass
-class GetTaskQueueInput:
-    """
-    Input dataclass for get task queue activity.
-
-    Attributes:
-    -----------
-    vnfr_uuid : str
-        The UUID of the VNF which is stored in the OSM vnfrs
-        collection in Mongo.
-
-    """
-
-    vnfr_uuid: str
-
-
-@dataclass
-class GetTaskQueueOutput:
-    """
-    Output dataclass for get task queue activity.
-
-    Attributes:
-    -----------
-    task_queue : str
-        Name of the queue which is used to Deploy VNF.
-    """
-
-    task_queue: str
-
-
-@dataclass
-class GetVnfRecordInput:
-    """
-    Input dataclass for get vnf details activity.
-
-    Attributes:
-    -----------
-    vnfr_uuid : str
-        The UUID of the VNF which is stored in the OSM vnfrs
-        collection in Mongo.
-    """
-
-    vnfr_uuid: str
-
-
-@dataclass
-class GetVnfRecordOutput:
-    """
-    Output dataclass for get vnf details activity.
-
-    Attributes:
-    -----------
-    vnfr : dict
-        VNF record retrieved from Database.
-
-    """
-
-    vnfr: dict
-
-
-@dataclass
-class GetVnfDescriptorInput:
-    """
-    Input dataclass for get vnf details activity.
-
-    Attributes:
-    -----------
-    vnfd_uuid : str
-        The UUID of the VNF descriptor which is stored in the OSM vnfds
-        collection in Mongo.
-    """
-
-    vnfd_uuid: str
-
-
-@dataclass
-class GetVnfDescriptorOutput:
-    """
-    Output dataclass for get vnf details activity.
-
-    Attributes:
-    -----------
-    vnfd : dict
-        VNF descriptor retrieved from Database.
-    """
-
-    vnfd: dict
-
-
-@dataclass
-class GetVnfDetailsInput:
-    """
-    Attributes:
-    -----------
-    ns_uuid : str
-        The UUID of the NS from which to retrieve the VNF records.
-    """
-
-    ns_uuid: str
-
-
-@dataclass
-class GetVnfDetailsOutput:
-    """
-    Attributes:
-    -----------
-    vnf_details: list[(vnfr_ids: str, vnf_member_index_ref: str), .. ]
-        List of tuples including VNF details associated with the NS.
-        Tuple(VNF record IDs, vnf_member_index_ref)
-    """
-
-    vnf_details: List[tuple]
diff --git a/osm_common/temporal/activities/base.py b/osm_common/temporal/activities/base.py
new file mode 100644 (file)
index 0000000..d207fe3
--- /dev/null
@@ -0,0 +1,23 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 logging
+
+
+class BaseActivity:
+    def __init__(self):
+        self.logger = logging.getLogger(f"lcm.act.{self.__class__.__name__}")
diff --git a/osm_common/temporal/activities/lcm.py b/osm_common/temporal/activities/lcm.py
new file mode 100644 (file)
index 0000000..9298bd1
--- /dev/null
@@ -0,0 +1,113 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 dataclasses import dataclass
+
+from osm_common.dbbase import DbBase
+from osm_common.temporal.activities.base import BaseActivity
+from osm_common.temporal.states import LcmOperationState
+
+
+class NsLcmNoOp(BaseActivity):
+    """
+    This is a simple No Operation Activity that simply logs the data
+    with which it was called. It can be used as a placeholder when
+    developing workflows, or can be enhanced with logic to throw
+    exceptions on specific conditions to test exception handling in
+    a workflow.
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflows that run as LCM operations.
+
+        Attributes:
+        -----------
+
+        nslcmop: dict
+            A dictionary representing the nslcmop record from the
+            database.
+        """
+
+        nslcmop: dict
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
+
+
+class UpdateNsLcmOperationState(BaseActivity):
+    """
+    Changes the state of a LCM operation task.  Should be done to
+    indicate progress, or completion of the task itself.
+
+    Collaborators:
+        DB Write:           nslcmops
+
+    Raises  (Retryable):
+        DbException         If the target DB record does not exist or DB is not reachable.
+
+    Activity Lifecycle:
+        This activity will not report a heartbeat due to its
+        short-running nature.
+        As this is a direct DB update, it is not recommended to have
+        any specific retry policy
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for updating LCM Operations in the Mongo nslcmops
+        collection.  The following attributes will be updated automatically
+          - statusEnteredTime
+          - _admin.modified
+
+        Attributes:
+        -----------
+        op_id: str
+            The operation (task) id for this activity.  This is the key
+            to the record in nslcmops collection that will be updated.
+
+        op_state : LcmOperationState
+            A representation of the state of the specified operation id,
+            such as PROCESSING, COMPLETED, or FAILED.
+
+        stage: str
+            Human readable checkpoint message, intended only to give the
+            user feedback.
+
+        error_message: str
+            Human readable error message if any failure occurred.
+
+        detailed_status : str
+            Human readable message providing additional details to the
+            operation state, such as the error message explaining why
+            the operation failed.
+        """
+
+        op_id: str
+        op_state: LcmOperationState
+        stage: str
+        error_message: str
+        detailed_status: str
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
diff --git a/osm_common/temporal/activities/ns.py b/osm_common/temporal/activities/ns.py
new file mode 100644 (file)
index 0000000..4f1f4fe
--- /dev/null
@@ -0,0 +1,180 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 dataclasses import dataclass
+from typing import List
+
+
+from osm_common.dbbase import DbBase
+from osm_common.temporal.activities.base import BaseActivity
+from osm_common.temporal.states import NsState
+
+
+class GetVnfDetails(BaseActivity):
+    """
+    Gets the list of VNF record IDs, VNF member-index-refs for a given NS record ID.
+
+    Collaborators:
+        DB Read:            vnfrs
+
+    Raises  (Retryable):
+        DbException         If the target DB record does not exist or DB is not reachable.
+
+    Activity Lifecycle:
+        This activity will not report a heartbeat due to its short-running nature.
+
+        Since this activity only reads from the DB, it is safe to retry, although
+        you may wish to have some back-off policy.
+    """
+
+    @dataclass
+    class Input:
+        """
+        Attributes:
+        -----------
+        ns_uuid : str
+            The UUID of the NS from which to retrieve the VNF records.
+        """
+
+        ns_uuid: str
+
+    @dataclass
+    class Output:
+        """
+        Attributes:
+        -----------
+        vnf_details: list[(vnfr_ids: str, vnf_member_index_ref: str), .. ]
+            List of tuples including VNF details associated with the NS.
+            Tuple(VNF record IDs, vnf_member_index_ref)
+        """
+
+        vnf_details: List[tuple]
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> Output:
+        raise NotImplementedError()
+
+
+class GetNsRecord(BaseActivity):
+    """Gets the NS record from Database.
+
+    Collaborators:
+        DB Read:     nsrs
+
+    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.
+
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for getting NS record activity.
+
+        Attributes:
+        -----------
+        nsr_uuid :
+            The UUID of the NS record which is stored in the OSM nsrs
+            collection in Mongo.
+
+        """
+
+        nsr_uuid: str
+
+    @dataclass
+    class Output:
+        """
+        Output dataclass for getting NS record activity.
+
+        Attributes:
+        -----------
+        nsr : dict
+            NS record retrieved from Database..
+
+        """
+
+        nsr: dict
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> Output:
+        raise NotImplementedError()
+
+
+class UpdateNsState(BaseActivity):
+    """
+    Changes the state of the NS itself.
+
+    Collaborators:
+        DB Write:           nsrs
+
+    Raises  (Retryable):
+        DbException         If the target DB record does not exist or DB is not reachable.
+
+    Activity Lifecycle:
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        As this is a direct DB update, it is not recommended to have
+        any specific retry policy
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for updating NS state in the DB
+
+        Attributes:
+        -----------
+        ns_uuid : str
+            The UUID of the NS as stored in the OSM ns
+            collection in Mongo
+
+        operational_state : NsState
+            A representation of the operational state (ENABLED or ERROR)
+            of the NS.
+
+        message : str
+            Human readable message providing additional details to the
+            operational state, such as the error message associated
+            with the ERROR operational_state.
+        """
+
+        ns_uuid: str
+        state: NsState
+        message: str
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
diff --git a/osm_common/temporal/activities/paas.py b/osm_common/temporal/activities/paas.py
new file mode 100644 (file)
index 0000000..a037282
--- /dev/null
@@ -0,0 +1,231 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 dataclasses import dataclass
+
+from osm_common.dbbase import DbBase
+from osm_common.temporal.activities.base import BaseActivity
+from osm_common.temporal.dataclasses_common import CharmInfo, VduComputeConstraints
+
+
+class TestVimConnectivity(BaseActivity):
+    """Validates the credentials by attempting to connect to the given Juju Controller.
+
+    Collaborators:
+        Juju Controller:    Connect only
+
+    Raises  (Retryable):
+        ApplicationError    If any of password, cacert, cloud_credentials is invalid
+                            or Juju controller is not reachable
+
+    Activity Lifecycle:
+        This activity should complete relatively quickly (in a few seconds).
+        However, it would be reasonable to wait more than 72 seconds (network timeout)
+        incase there are network issues.
+
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        It is recommended, although not necessary to implement a
+        back-off strategy for this activity, as it will naturally block
+        and wait on each connection attempt.
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for the Test Vim Connectivity Ativity
+
+        Attributes:
+        -----------
+        vim_uuid : str
+            The UUID of the VIM account as stored in the OSM vim
+            collection in Mongo
+        """
+
+        vim_uuid: str
+
+    def __init__(self, juju_controller):
+        super().__init__()
+        self.juju_controller = juju_controller
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
+
+
+class CreateModel(BaseActivity):
+    """Connects to Juju Controller. Creates a new model.
+
+    Collaborators:
+        DB Read:            vim_accounts
+        Juju Controller:    Connect and create model.
+
+    Raises  (Retryable):
+        ApplicationError    If Juju controller is not reachable.
+                            If the model already exists.
+
+    Activity Lifecycle:
+        This activity should complete relatively quickly (in a few seconds).
+        However, it would be reasonable to wait more than 72 seconds (network timeout)
+        incase there are network issues.
+
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        It is recommended, although not necessary to implement a
+        back-off strategy for this activity, as it will naturally block
+        and wait on each connection attempt.
+    """
+
+    @dataclass
+    class Input:
+        """
+        Contains the information related to a model.
+
+        Attributes:
+        -----------
+        vim_uuid : str
+            The UUID of the VIM as stored in the OSM vim_accounts
+            collection in Mongo.
+
+        model_name : str
+            Name of the Juju model used to deploy charms.
+        """
+
+        vim_uuid: str
+        model_name: str
+
+    def __init__(self, db: DbBase, juju_controller):
+        super().__init__()
+        self.db: DbBase = db
+        self.juju_controller = juju_controller
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
+
+
+class DeployCharm(BaseActivity):
+    """Deploys a charm.
+
+    Collaborators:
+        Juju Controller:    Connect and deploy charm
+
+    Raises  (Retryable):
+        ApplicationError    If Juju controller is not reachable
+                            If application already exists
+
+    Activity Lifecycle:
+        This activity should complete relatively quickly (in a few seconds).
+        However, it would be reasonable to wait more than 72 seconds (network timeout)
+        incase there are network issues.
+
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        It is recommended, although not necessary to implement a
+        back-off strategy for this activity, as it will naturally block
+        and wait on each connection attempt.
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflow that instantiates a VDU.
+
+        vim_uuid: str
+
+        model_name: str
+
+        charm_info : CharmInfo
+
+        constraints: VduComputeConstraints
+
+        cloud: VIM cloud type
+
+        config: Config details of application
+        """
+
+        vim_uuid: str
+        model_name: str
+        charm_info: CharmInfo
+        constraints: VduComputeConstraints
+        cloud: str
+        config: dict
+
+    def __init__(self, juju_controller):
+        super().__init__()
+        self.juju_controller = juju_controller
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
+
+
+class CheckCharmStatus(BaseActivity):
+    """Checks the ready status of the charm.  This activity will block until the status of
+    the application is either "active" or "blocked".  Additionally, it also blocks until
+    the workload status of each of its units is also either "active" or "blocked".
+
+    Collaborators:
+        Juju Controller:    Connect to controller and check charm status.
+
+    Raises  (Retryable):
+        ApplicationError    If any of password, cacert, cloud_credentials is invalid
+                            or Juju controller is not reachable
+
+    Activity Lifecycle:
+        This activity will continue indefinitely until the specified charm deployment
+        has reached a ready state.  Heartbeats are performed to ensure this activity
+        does not time out.
+
+        A start-to-close of something reasonable (such as 5 minutes) should be implemented
+        at the workflow level and such a timeout shall trigger workflow failure logic.
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for checking on a specific charm's deployment
+        status
+
+        Attributes:
+        -----------
+        vim_uuid : str
+            The UUID of the VIM as stored in the OSM vim_accounts
+            collection in Mongo.
+
+        model_name : str
+            Name of the model to create in Juju.
+
+        application_name : str
+            Name of the application that the state is going to be
+            awaited.
+
+        poll_interval : int (optional)
+            Time, in seconds, to wait between status checks.
+        """
+
+        vim_uuid: str
+        model_name: str
+        application_name: str
+        poll_interval: int = 1
+
+    def __init__(self, juju_controller):
+        super().__init__()
+        self.juju_controller = juju_controller
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
diff --git a/osm_common/temporal/activities/vim.py b/osm_common/temporal/activities/vim.py
new file mode 100644 (file)
index 0000000..e52b6a1
--- /dev/null
@@ -0,0 +1,174 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 dataclasses import dataclass
+
+from osm_common.dbbase import DbBase
+from osm_common.temporal.activities.base import BaseActivity
+from osm_common.temporal.states import VimOperationState, VimState
+
+
+class UpdateVimState(BaseActivity):
+    """
+    Changes the state of the VIM itself.  Should be either
+    ENABLED or ERROR, however this activity does not validate
+    the state as no validation was done in OSM previously.
+
+    Collaborators:
+        DB Write:           vim_accounts
+
+    Raises  (Retryable):
+        DbException         If the target DB record does not exist or DB is not reachable.
+
+    Activity Lifecycle:
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        As this is a direct DB update, it is not recommended to have
+        any specific retry policy
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for updating VIM state in the DB
+
+        Attributes:
+        -----------
+        vim_uuid : str
+            The UUID of the VIM account as stored in the OSM vim
+            collection in Mongo
+
+        operational_state : VimState
+            A representation of the operational state (ENABLED or ERROR)
+            of the VIM.
+
+        message : str
+            Human readable message providing additional details to the
+            operational state, such as the error message associated
+            with the ERROR operational_state.
+        """
+
+        vim_uuid: str
+        operational_state: VimState
+        message: str
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
+
+
+class UpdateVimOperationState(BaseActivity):
+    """
+    Changes the state of a VIM operation task.  Should be done to
+    indicate progress, or completion of the task itself.
+
+    Collaborators:
+        DB Write:           vim_accounts
+
+    Raises  (Retryable):
+        DbException         If the target DB record does not exist or DB is not reachable.
+
+    Activity Lifecycle:
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        As this is a direct DB update, it is not recommended to have
+        any specific retry policy
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for updating VIM Operations in the Mongo VIM
+        collection.
+
+        Attributes:
+        -----------
+        vim_uuid : str
+            The UUID of the VIM account as stored in the OSM vim
+            collection in Mongo
+
+        op_id: str
+            The operation (task) id for this workflow.  This is used
+            to update the status of the operation in Mongo vim collection.
+
+        op_state : VimOperationState
+            A representation of the state of the specified operation id,
+            such as COMPLETED, or FAILED.
+
+        message : str
+            Human readable message providing additional details to the
+            operation state, such as the error message explaining why
+            the operation failed.
+        """
+
+        vim_uuid: str
+        op_id: str
+        op_state: VimOperationState
+        message: str
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
+
+
+class DeleteVimRecord(BaseActivity):
+    """
+    Deletes the VIM record from the database.
+
+    Collaborators:
+        DB Delete:           vim_accounts
+
+    Raises (Retryable):
+        DbException         If the target DB record does not exist or DB is not reachable.
+
+    Activity Lifecycle:
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        As this is a direct DB update, it is not recommended to have
+        any specific retry policy
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for deleting vim record from the database
+
+        Attributes:
+        -----------
+        vim_uuid : str
+            The UUID of the VIM account as stored in the OSM vim
+            collection in Mongo
+
+        """
+
+        vim_uuid: str
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
diff --git a/osm_common/temporal/activities/vnf.py b/osm_common/temporal/activities/vnf.py
new file mode 100644 (file)
index 0000000..81f2982
--- /dev/null
@@ -0,0 +1,420 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 dataclasses import dataclass
+
+from osm_common.dbbase import DbBase
+from osm_common.temporal.activities.base import BaseActivity
+from osm_common.temporal.states import VnfInstantiationState, VnfState
+
+
+class ChangeVnfState(BaseActivity):
+    """Updates the VNF State in VNFR.
+
+    Collaborators:
+        DB Write:           vnfrs
+
+    Raises (retryable):
+        DbException: If DB access/update fails, the collection or DB record ID does not exist.
+
+    Activity Lifecycle:
+        This activity should complete relatively quickly (less than a
+        second). However, it would be reasonable to wait up to 10
+        seconds.
+
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        It is not necessary to implement a back-off strategy for this
+        activity, the operation is idempotent.
+
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for changing VNF State.
+
+        Attributes:
+        -----------
+        vnfr_uuid : str
+            The UUID of the VNF which is stored in the OSM vnfrs
+            collection in Mongo.
+
+        state : VnfState
+            A representation of the VNF state (STOPPED or STARTED).
+        """
+
+        vnfr_uuid: str
+        state: VnfState
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
+
+
+class ChangeVnfInstantiationState(BaseActivity):
+    """Updates the VNF Instantiation State in VNFR.
+
+    Collaborators:
+        DB Write:           vnfrs
+
+    Raises (retryable):
+        DbException: If DB access or update fails, the collection or DB record ID does not exist.
+
+    Activity Lifecycle:
+        This activity should complete relatively quickly (less than a
+        second). However, it would be reasonable to wait up to 10
+        seconds.
+
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        It is not necessary to implement a back-off strategy for this
+        activity, the operation is idempotent.
+
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for changing VNF Instantiation State.
+
+        Attributes:
+        -----------
+        vnfr_uuid : str
+            The UUID of the VNF which is stored in the OSM vnfrs
+            collection in Mongo.
+
+        state : VnfInstantiationState
+            A representation of the VNF instantiation state (NOT_INSTANTIATED or INSTANTIATED).
+
+        """
+
+        vnfr_uuid: str
+        state: VnfInstantiationState
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
+
+
+class GetVnfRecord(BaseActivity):
+    """Gets the VNF record and VNF descriptor from Database.
+
+    Collaborators:
+        DB read:           vnfrs, 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.
+
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for get vnf details activity.
+
+        Attributes:
+        -----------
+        vnfr_uuid : str
+            The UUID of the VNF which is stored in the OSM vnfrs
+            collection in Mongo.
+        """
+
+        vnfr_uuid: str
+
+    @dataclass
+    class Output:
+        """
+        Output dataclass for get vnf details activity.
+
+        Attributes:
+        -----------
+        vnf_details: list[(vnfr_ids: str, vnf_member_index_ref: str), .. ]
+            List of tuples including VNF details associated with the NS.
+            Tuple(VNF record IDs, vnf_member_index_ref)
+        """
+
+        vnfr: dict
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> Output:
+        raise NotImplementedError()
+
+
+class GetVnfDescriptor(BaseActivity):
+    """Gets the VNF record and VNF descriptor from Database.
+
+    Collaborators:
+        DB read:           vnfrs
+
+    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.
+
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for get vnf descriptor activity.
+
+        Attributes:
+        -----------
+        vnfd_uuid : str
+            The UUID of the VNF descriptor which is stored in the OSM vnfds
+            collection in Mongo.
+        """
+
+        vnfd_uuid: str
+
+    @dataclass
+    class Output:
+        """
+        Output dataclass for get vnf details activity.
+
+        Attributes:
+        -----------
+        vnfd : dict
+            VNF descriptor retrieved from Database.
+        """
+
+        vnfd: dict
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> Output:
+        raise NotImplementedError()
+
+
+class SendNotificationForVnf(BaseActivity):
+    """Perform Notification operations."""
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for sending notifications for change in VNF Instantiation State.
+
+        Attributes:
+        -----------
+        vnfr_uuid : str
+            The UUID of the VNF which is stored in the OSM vnfrs
+            collection in Mongo.
+
+        state : VnfInstantiationState
+            A representation of the VNF instantiation state (NOT_INSTANTIATED or INSTANTIATED).
+
+        """
+
+        vnfr_uuid: str
+        state: VnfState
+
+    async def __call__(self, activity_input: Input):
+        raise NotImplementedError()
+
+
+class GetTaskQueue(BaseActivity):
+    """Finds the appropriate task queue according to VIM type of VNF.
+
+    Collaborators:
+        DB read:           vim_accounts, vnfrs
+
+    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 a
+        second). However, it would be reasonable to wait up to 10
+        seconds.
+
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        It is not necessary to implement a back-off strategy for this
+        activity, the operation is idempotent.
+
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for get task queue activity.
+
+        Attributes:
+        -----------
+        vnfr_uuid : str
+            The UUID of the VNF which is stored in the OSM vnfrs
+            collection in Mongo.
+
+        """
+
+        vnfr_uuid: str
+
+    @dataclass
+    class Output:
+        """
+        Output dataclass for get task queue activity.
+
+        Attributes:
+        -----------
+        task_queue : str
+            Name of the queue which is used to Deploy VNF.
+        """
+
+        task_queue: str
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> Output:
+        raise NotImplementedError()
+
+
+class GetVimCloud(BaseActivity):
+    """Finds the cloud by checking the VIM account of VNF.
+
+    Collaborators:
+        DB Read:  vnfrs, vim_accounts
+
+    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 a
+        second). However, it would be reasonable to wait up to 10
+        seconds.
+
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        It is not necessary to implement a back-off strategy for this
+        activity, the operation is idempotent.
+
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for get vim cloud activity.
+
+        Attributes:
+        -----------
+        vnfr_uuid : str
+            The UUID of the VNF which is stored in the OSM vnfrs
+            collection in Mongo.
+
+        """
+
+        vnfr_uuid: str
+
+    @dataclass
+    class Output:
+        """
+        Output dataclass for get vim cloud activity.
+
+        Attributes:
+        -----------
+        cloud : str
+            Type of the cloud which is used to Deploy VNF.
+        """
+
+        cloud: str
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> Output:
+        raise NotImplementedError()
+
+
+class SetVnfModel(BaseActivity):
+    """Updates the model name of VNF in VNFR.
+
+    Collaborators:
+        DB Write:           vnfrs
+
+    Raises (retryable):
+        DbException: If DB access or update fails, the collection or DB record ID does not exist.
+
+    Activity Lifecycle:
+        This activity should complete relatively quickly (less than a
+        second). However, it would be reasonable to wait up to 10
+        seconds.
+
+        This activity will not report a heartbeat due to its
+        short-running nature.
+
+        It is not necessary to implement a back-off strategy for this
+        activity, the operation is idempotent.
+
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflow that instantiates a VNF.
+
+        Attributes:
+        -----------
+        vnfr_uuid : str
+            The UUID of the VNF which is stored in the OSM vnfrs
+            collection in Mongo.
+
+        model_name: str
+
+        """
+
+        vnfr_uuid: str
+        model_name: str
+
+    def __init__(self, db: DbBase):
+        super().__init__()
+        self.db: DbBase = db
+
+    async def __call__(self, activity_input: Input) -> None:
+        raise NotImplementedError()
diff --git a/osm_common/temporal/dataclasses_common.py b/osm_common/temporal/dataclasses_common.py
new file mode 100644 (file)
index 0000000..fc06643
--- /dev/null
@@ -0,0 +1,53 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 dataclasses import dataclass
+
+
+@dataclass
+class CharmInfo:
+    """
+    Input dataclass for
+
+    Attributes:
+    -----------
+    app_name : str
+
+    channel: str
+
+    entity_url: str
+    """
+
+    app_name: str
+    channel: str
+    entity_url: str
+
+
+@dataclass
+class VduComputeConstraints:
+    """
+    Input dataclass for VDU constraints
+
+    Attributes:
+    -----------
+    cores : int (Number of virtual CPUs)
+
+    mem: int (GB)
+    """
+
+    cores: int
+    mem: int
diff --git a/osm_common/temporal/states.py b/osm_common/temporal/states.py
new file mode 100644 (file)
index 0000000..1c4c896
--- /dev/null
@@ -0,0 +1,57 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 enum import auto, IntEnum
+
+
+class VimState(IntEnum):
+    PROCESSING = auto()
+    ENABLED = auto()
+    ERROR = auto()
+
+
+class VimOperationState(IntEnum):
+    COMPLETED = auto()
+    FAILED = auto()
+
+
+class NsState(IntEnum):
+    PROCESSING = auto()
+    INSTANTIATED = auto()
+    ERROR = auto()
+
+
+class VnfLcmOperationState(IntEnum):
+    PROCESSING = auto()
+    COMPLETED = auto()
+    FAILED = auto()
+
+
+class VnfInstantiationState(IntEnum):
+    NOT_INSTANTIATED = auto()
+    INSTANTIATED = auto()
+
+
+class VnfState(IntEnum):
+    STOPPED = auto()
+    STARTED = auto()
+
+
+class LcmOperationState(IntEnum):
+    PROCESSING = auto()
+    COMPLETED = auto()
+    FAILED = auto()
diff --git a/osm_common/temporal/workflows/base.py b/osm_common/temporal/workflows/base.py
new file mode 100644 (file)
index 0000000..44b73be
--- /dev/null
@@ -0,0 +1,24 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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
+import logging
+
+
+class BaseWorkflow(ABC):
+    def __init__(self):
+        self.logger = logging.getLogger(f"lcm.wfl.{self.__class__.__name__}")
diff --git a/osm_common/temporal/workflows/lcm.py b/osm_common/temporal/workflows/lcm.py
new file mode 100644 (file)
index 0000000..ee5b6ad
--- /dev/null
@@ -0,0 +1,167 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 abstractmethod
+from dataclasses import dataclass
+from datetime import timedelta
+
+from osm_common.temporal.activities.lcm import UpdateNsLcmOperationState
+from osm_common.temporal.workflows.base import BaseWorkflow
+from osm_common.temporal.states import LcmOperationState
+from temporalio import workflow
+from temporalio.common import RetryPolicy
+from temporalio.exceptions import ActivityError, ChildWorkflowError
+
+
+class LcmOperationWorkflow(BaseWorkflow):
+    """
+    An abstract base class representing a Lifecycle Management Operation.  Any
+    workflows that need LCM OP control should extend this class and implement
+    the workflow method.
+
+    Methods
+    -------
+
+    @abstractmethod run(self, workflow_input: Input)
+        Method for subclasses to implement the actual workflow that is being
+        wrapped in this operation.
+
+    @workflow.run wrap_nslcmop(workflow_input: Input)
+        Must be implemented in every subclass exactly as follows:
+        @workflow.run
+        async def wrap_nslcmop(self, workflow_input: Input) -> None:
+            await super().wrap_nslcmop(workflow_input=workflow_input)
+    """
+
+    retry_policy = RetryPolicy(maximum_attempts=3)
+    no_retry_policy = RetryPolicy(maximum_attempts=1)
+    default_schedule_to_close_timeout = timedelta(minutes=10)
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflows that run as LCM operations.
+
+        Attributes:
+        -----------
+
+        nslcmop: dict
+            A dictionary representing the nslcmop record from the
+            database.
+        """
+
+        nslcmop: dict
+
+    def __init__(self):
+        super().__init__()
+        self.op_id = None
+        self.stage = ""
+
+    async def wrap_nslcmop(self, workflow_input: Input):
+        self.op_id = workflow_input.nslcmop["_id"]
+        await self.update_operation_state(LcmOperationState.PROCESSING)
+        try:
+            await self.run(workflow_input=workflow_input)
+
+        except ActivityError as e:
+            err_details = str(e.cause.with_traceback(e.__traceback__))
+            self.logger.error(err_details)
+            await self.update_operation_state(
+                LcmOperationState.FAILED,
+                error_message=str(e.cause.message),
+                detailed_status=err_details,
+            )
+            raise e
+
+        except ChildWorkflowError as e:
+            err_details = str(e.cause.with_traceback(e.cause.__traceback__))
+            self.logger.error(err_details)
+            await self.update_operation_state(
+                LcmOperationState.FAILED,
+                error_message=str(e.cause.message),
+                detailed_status=err_details,
+            )
+            raise e
+
+        except Exception as e:
+            self.logger.exception(e)
+            await self.update_operation_state(
+                LcmOperationState.FAILED,
+                error_message=str(e),
+                detailed_status=str(e),
+            )
+            raise e
+
+        await self.update_operation_state(LcmOperationState.COMPLETED)
+
+    async def update_operation_state(
+        self,
+        op_state: LcmOperationState,
+        stage: str = None,
+        error_message: str = "",
+        detailed_status: str = "",
+    ) -> None:
+        if stage is not None:
+            self.stage = stage
+        update_input = UpdateNsLcmOperationState.Input(
+            op_id=self.op_id,
+            op_state=op_state,
+            stage=self.stage,
+            error_message=error_message,
+            detailed_status=detailed_status,
+        )
+        await workflow.execute_activity(
+            activity=UpdateNsLcmOperationState.__name__,
+            arg=update_input,
+            activity_id=f"{UpdateNsLcmOperationState.__name__}-{self.op_id}",
+            schedule_to_close_timeout=LcmOperationWorkflow.default_schedule_to_close_timeout,
+            retry_policy=LcmOperationWorkflow.retry_policy,
+        )
+
+    @abstractmethod
+    async def run(self, workflow_input: Input):
+        pass
+
+
+class NsNoOpWorkflow(LcmOperationWorkflow):
+    """
+    This is a simple No Operation workflow that simply calls a No Operation
+    activity.  It can be used as a placeholder when developing workflows.
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflows that run as LCM operations.
+
+        Attributes:
+        -----------
+
+        nslcmop: dict
+            A dictionary representing the nslcmop record from the
+            database.
+        """
+
+        nslcmop: dict
+
+    @abstractmethod
+    async def wrap_nslcmop(self, workflow_input: Input) -> None:
+        pass
+
+    @abstractmethod
+    async def run(self, workflow_input: Input) -> None:
+        pass
diff --git a/osm_common/temporal/workflows/ns.py b/osm_common/temporal/workflows/ns.py
new file mode 100644 (file)
index 0000000..acd2670
--- /dev/null
@@ -0,0 +1,48 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 abstractmethod
+from dataclasses import dataclass
+
+from osm_common.temporal.workflows.lcm import LcmOperationWorkflow
+
+
+class NsInstantiateWorkflow(LcmOperationWorkflow):
+    """Instantiate a NS"""
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflows that run as LCM operations.
+
+        Attributes:
+        -----------
+
+        nslcmop: dict
+            A dictionary representing the nslcmop record from the
+            database.
+        """
+
+        nslcmop: dict
+
+    @abstractmethod
+    async def wrap_nslcmop(self, workflow_input) -> None:
+        pass
+
+    @abstractmethod
+    async def run(self, workflow_input: Input) -> None:
+        pass
diff --git a/osm_common/temporal/workflows/vdu.py b/osm_common/temporal/workflows/vdu.py
new file mode 100644 (file)
index 0000000..e7f2f84
--- /dev/null
@@ -0,0 +1,55 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 abstractmethod
+from dataclasses import dataclass
+
+from osm_common.temporal.dataclasses_common import CharmInfo, VduComputeConstraints
+from osm_common.temporal.workflows.base import BaseWorkflow
+
+
+class VduInstantiateWorkflow(BaseWorkflow):
+    """Instantiate a VDU"""
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflow that instantiates a VDU.
+
+        vim_uuid: str
+
+        model_name: str
+
+        charm_info : CharmInfo
+
+        constraints: VduComputeConstraints
+
+        cloud: VIM cloud type
+
+        config: Config details of application
+        """
+
+        vim_uuid: str
+        model_name: str
+        charm_info: CharmInfo
+        constraints: VduComputeConstraints
+        cloud: str
+        config: dict
+
+    @abstractmethod
+    async def run(self, workflow_input: Input) -> None:
+        pass
diff --git a/osm_common/temporal/workflows/vim.py b/osm_common/temporal/workflows/vim.py
new file mode 100644 (file)
index 0000000..89b19af
--- /dev/null
@@ -0,0 +1,108 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 abstractmethod
+from dataclasses import dataclass
+
+from osm_common.temporal.workflows.base import BaseWorkflow
+
+
+class VimCreateWorkflow(BaseWorkflow):
+    """Creates VIM account by validating the VIM connectivity."""
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflows that perform operations
+        (create, update, delete) on VIMs.
+
+        Attributes:
+        -----------
+        vim_uuid : str
+            The UUID of the VIM account as stored in the OSM vim
+            collection in Mongo
+
+        op_id: str
+            The operation (task) id for this workflow.  This is used
+            by the workflow at the end to update the status of the
+            operation in Mongo vim collection.
+        """
+
+        vim_uuid: str
+        op_id: str
+
+    @abstractmethod
+    async def run(self, workflow_input: Input) -> None:
+        pass
+
+
+class VimUpdateWorkflow(VimCreateWorkflow):
+    """Updates VIM account state by validating the VIM connectivity."""
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflows that perform operations
+        (create, update, delete) on VIMs.
+
+        Attributes:
+        -----------
+        vim_uuid : str
+            The UUID of the VIM account as stored in the OSM vim
+            collection in Mongo
+
+        op_id: str
+            The operation (task) id for this workflow.  This is used
+            by the workflow at the end to update the status of the
+            operation in Mongo vim collection.
+        """
+
+        vim_uuid: str
+        op_id: str
+
+    @abstractmethod
+    async def run(self, workflow_input: Input) -> None:
+        pass
+
+
+class VimDeleteWorkflow(BaseWorkflow):
+    """Deletes VIM accounts."""
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflows that perform operations
+        (create, update, delete) on VIMs.
+
+        Attributes:
+        -----------
+        vim_uuid : str
+            The UUID of the VIM account as stored in the OSM vim
+            collection in Mongo
+
+        op_id: str
+            The operation (task) id for this workflow.  This is used
+            by the workflow at the end to update the status of the
+            operation in Mongo vim collection.
+        """
+
+        vim_uuid: str
+        op_id: str
+
+    @abstractmethod
+    async def run(self, workflow_input: Input) -> None:
+        pass
diff --git a/osm_common/temporal/workflows/vnf.py b/osm_common/temporal/workflows/vnf.py
new file mode 100644 (file)
index 0000000..365f953
--- /dev/null
@@ -0,0 +1,87 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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 abstractmethod
+from dataclasses import dataclass
+
+from osm_common.temporal.workflows.base import BaseWorkflow
+
+
+class VnfInstantiateWorkflow(BaseWorkflow):
+    """Instantiate a VNF.
+
+    Workflow Identifier:
+        It is recommended that the ID for the VNF is referred as a workflow
+        ID when invoking this workflow.
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflow that instantiates a VNF.
+
+        Attributes:
+        -----------
+        vnfr_uuid : str
+            The UUID of the VNF which is stored in the OSM vnfrs
+            collection in Mongo.
+
+        model_name: str
+
+        instantiation_config: dict
+            The instantiation configuration of the VNF
+
+        """
+
+        vnfr_uuid: str
+        model_name: str
+        instantiation_config: dict
+
+    @abstractmethod
+    async def run(self, workflow_input: Input) -> None:
+        pass
+
+
+class VnfPrepareWorkflow(BaseWorkflow):
+    """Prepare a VNF.
+
+    Workflow Identifier:
+        It is recommended that the ID for the VNF is referred as a workflow
+        ID when invoking this workflow.
+    """
+
+    @dataclass
+    class Input:
+        """
+        Input dataclass for workflow that instantiates a VNF.
+
+        Attributes:
+        -----------
+        vnfr_uuid : str
+            The UUID of the VNF which is stored in the OSM vnfrs
+            collection in Mongo.
+
+        model_name: str
+
+        """
+
+        vnfr_uuid: str
+        model_name: str
+
+    @abstractmethod
+    async def run(self, workflow_input: Input) -> None:
+        pass
diff --git a/osm_common/temporal_constants.py b/osm_common/temporal_constants.py
deleted file mode 100644 (file)
index 9a3af23..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#######################################################################################
-# Copyright ETSI Contributors and Others.
-#
-# 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.
-#######################################################################################
-# Task Queues
-LCM_TASK_QUEUE = "lcm-task-queue"
-
-# Vim Type-Task Queue Mappings
-VIM_TYPE_TASK_QUEUE_MAPPINGS = {
-    "paas": LCM_TASK_QUEUE,
-}
-
-# Activities
-ACTIVITY_NSLCM_NO_OP = "nslcm-no-op"
-ACTIVITY_EXECUTE_NS_LCM_WORKFLOW = "execute-ns-lcm-workflow"
-ACTIVITY_UPDATE_LCM_OPERATION_STATE = "update-lcm-operation-state"
-ACTIVITY_DELETE_VIM = "delete-vim"
-ACTIVITY_TEST_VIM_CONNECTIVITY = "test-vim-connectivity"
-ACTIVITY_UPDATE_VIM_OPERATION_STATE = "update-vim-operation-state"
-ACTIVITY_UPDATE_VIM_STATE = "update-vim-state"
-ACTIVITY_GET_NS_RECORD = "get-ns-record"
-ACTIVITY_GET_VNF_DETAILS = "get-vnf-details"
-ACTIVITY_UPDATE_NS_STATE = "update-ns-state"
-ACTIVITY_CREATE_MODEL = "create-model"
-ACTIVITY_GET_MODEL_INFO = "get-model-info"
-ACTIVITY_DEPLOY_CHARM = "deploy-charm"
-ACTIVITY_CHECK_CHARM_STATUS = "check-charm-status"
-ACTIVITY_CHANGE_VNF_STATE = "change-vnf-state"
-ACTIVITY_CHANGE_VNF_INSTANTIATION_STATE = "change-vnf-instantiation-state"
-ACTIVITY_SEND_NOTIFICATION_FOR_VNF = "send-notification-for-vnf"
-ACTIVITY_GET_TASK_QUEUE = "get-task-queue"
-ACTIVITY_GET_VNF_RECORD = "get-vnf-record"
-ACTIVITY_GET_VNF_DESCRIPTOR = "get-vnf-descriptor"
-ACTIVITY_SET_VNF_MODEL = "set-vnf-model"
-ACTIVITY_GET_VIM_CLOUD = "get-vim-cloud"
-
-# Workflows
-WORKFLOW_NSLCM_NO_OP = "nslcm-no-op"
-WORKFLOW_VIM_CREATE = "vim-create"
-WORKFLOW_VIM_UPDATE = "vim-update"
-WORKFLOW_VIM_DELETE = "vim-delete"
-WORKFLOW_NS_INSTANTIATE = "ns-instantiate"
-WORKFLOW_VDU_INSTANTIATE = "vdu-instantiate"
-WORKFLOW_VNF_INSTANTIATE = "vnf-instantiate"
-WORKFLOW_VNF_PREPARE = "vnf-prepare"
diff --git a/osm_common/temporal_task_queues/task_queues_mappings.py b/osm_common/temporal_task_queues/task_queues_mappings.py
new file mode 100644 (file)
index 0000000..6a644a3
--- /dev/null
@@ -0,0 +1,24 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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.
+#######################################################################################
+
+# Task Queues
+LCM_TASK_QUEUE = "lcm-task-queue"
+
+# Vim Type-Task Queue Mappings
+VIM_TYPE_TASK_QUEUE_MAPPINGS = {
+    "paas": LCM_TASK_QUEUE,
+}