VimDeleteWorkflow,
VimUpdateWorkflow,
)
+from osm_lcm.temporal.vdu_workflows import VduInstantiateWorkflow
from temporalio.client import Client
from temporalio.worker import Worker
f"{self.main_config.temporal.host}:{str(self.main_config.temporal.port)}"
)
client = await Client.connect(temporal_api)
- data_activity_instance = VimDbActivity(self.db)
+ vim_data_activity_instance = VimDbActivity(self.db)
paas_connector_instance = JujuPaasConnector(self.db)
nslcm_activity_instance = NsLcmActivity(self.db)
VimCreateWorkflow,
VimDeleteWorkflow,
VimUpdateWorkflow,
+ VduInstantiateWorkflow,
]
activities = [
- data_activity_instance.update_vim_operation_state,
- data_activity_instance.update_vim_state,
- data_activity_instance.delete_vim_record,
+ vim_data_activity_instance.update_vim_operation_state,
+ vim_data_activity_instance.update_vim_state,
+ vim_data_activity_instance.delete_vim_record,
nslcm_activity_instance.update_ns_lcm_operation_state,
nslcm_activity_instance.no_op,
paas_connector_instance.test_vim_connectivity,
+ paas_connector_instance.create_model_if_doesnt_exist,
+ paas_connector_instance.deploy_charm,
+ paas_connector_instance.check_charm_status,
]
# Check if we are running under a debugger
--- /dev/null
+#######################################################################################
+# 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 datetime import timedelta
+import logging
+from temporalio import workflow
+from temporalio.common import RetryPolicy
+
+from osm_common.dataclasses.temporal_dataclasses import (
+ VduInstantiateInput,
+ CreateModelInput,
+)
+from osm_common.temporal_constants import (
+ WORKFLOW_VDU_INSTANTIATE,
+ ACTIVITY_CREATE_MODEL_IF_DOESNT_EXIST,
+ ACTIVITY_DEPLOY_CHARM,
+ ACTIVITY_CHECK_CHARM_STATUS,
+ LCM_TASK_QUEUE,
+)
+
+_SANDBOXED = False
+retry_policy = RetryPolicy(maximum_attempts=3)
+default_schedule_to_close_timeout = timedelta(minutes=10)
+
+workflow.logger = logging.getLogger("lcm.temporal.vdu_workflows")
+
+
+@workflow.defn(name=WORKFLOW_VDU_INSTANTIATE, sandboxed=_SANDBOXED)
+class VduInstantiateWorkflow:
+ """Instantiate a VDU"""
+
+ @workflow.run
+ async def run(self, input: VduInstantiateInput) -> None:
+ try:
+ await workflow.execute_activity(
+ activity=ACTIVITY_CREATE_MODEL_IF_DOESNT_EXIST,
+ arg=CreateModelInput(input.vim_uuid, input.model_name),
+ activity_id=f"{ACTIVITY_CREATE_MODEL_IF_DOESNT_EXIST}-{input.vim_uuid}",
+ task_queue=LCM_TASK_QUEUE,
+ schedule_to_close_timeout=default_schedule_to_close_timeout,
+ retry_policy=retry_policy,
+ )
+
+ await workflow.execute_activity(
+ activity=ACTIVITY_DEPLOY_CHARM,
+ arg=input,
+ activity_id=f"{ACTIVITY_DEPLOY_CHARM}-{input.vim_uuid}",
+ task_queue=LCM_TASK_QUEUE,
+ schedule_to_close_timeout=default_schedule_to_close_timeout,
+ retry_policy=retry_policy,
+ )
+
+ await workflow.execute_activity(
+ activity=ACTIVITY_CHECK_CHARM_STATUS,
+ arg=input,
+ activity_id=f"{ACTIVITY_CHECK_CHARM_STATUS}-{input.vim_uuid}",
+ task_queue=LCM_TASK_QUEUE,
+ schedule_to_close_timeout=default_schedule_to_close_timeout,
+ retry_policy=retry_policy,
+ )
+
+ except Exception as e:
+ workflow.logger.error(f"{WORKFLOW_VDU_INSTANTIATE} failed with {str(e)}")
+ raise e
ACTIVITY_TEST_VIM_CONNECTIVITY,
ACTIVITY_UPDATE_VIM_OPERATION_STATE,
ACTIVITY_UPDATE_VIM_STATE,
+ ACTIVITY_CREATE_MODEL_IF_DOESNT_EXIST,
+ ACTIVITY_DEPLOY_CHARM,
+ ACTIVITY_CHECK_CHARM_STATUS,
)
from osm_common.dataclasses.temporal_dataclasses import (
DeleteVimInput,
TestVimConnectivityInput,
UpdateVimOperationStateInput,
UpdateVimStateInput,
+ CreateModelInput,
+ VduInstantiateInput,
)
activity.logger = logging.getLogger("lcm.temporal.vim_activities")
endpoint, username, password, cacert, cloud_name, cloud_credentials
)
+ def _get_libjuju(self, vim_uuid):
+ connection_info = self._get_connection_info(vim_uuid)
+ return Libjuju(connection_info)
+
@activity.defn(name=ACTIVITY_TEST_VIM_CONNECTIVITY)
async def test_vim_connectivity(
self, test_connectivity_input: TestVimConnectivityInput
vim_id = test_connectivity_input.vim_uuid
controller = None
try:
- connection_info = self._get_connection_info(vim_id)
- libjuju = Libjuju(connection_info)
+ libjuju = self._get_libjuju(vim_id)
controller = await libjuju.get_controller()
message = f"Connection to juju controller succeeded for {vim_id}"
activity.logger.info(message)
finally:
await libjuju.disconnect_controller(controller)
+ @activity.defn(name=ACTIVITY_CREATE_MODEL_IF_DOESNT_EXIST)
+ async def create_model_if_doesnt_exist(
+ self, create_model_input: CreateModelInput
+ ) -> None:
+ """Connects to Juju Controller. Create a new model if model_name does not exist
+
+ Collaborators:
+ DB Read: vim_accounts
+ Juju Controller: Connect and create model.
+
+ Raises (Retryable):
+ ApplicationError If 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.
+ """
+ model_name = create_model_input.model_name
+ libjuju = self._get_libjuju(create_model_input.vim_uuid)
+ await libjuju.add_model(model_name)
+
+ @activity.defn(name=ACTIVITY_DEPLOY_CHARM)
+ async def deploy_charm(self, deploy_charm_input: VduInstantiateInput) -> None:
+ """Deploys a charm.
+
+ Collaborators:
+ DB Read: vim_accounts
+ Juju Controller: Connect and deploy charm
+
+ Raises (Retryable):
+ ApplicationError If 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.
+ """
+ model_name = deploy_charm_input.model_name
+ libjuju = self._get_libjuju(deploy_charm_input.vim_uuid)
+ charm_info = deploy_charm_input.charm_info
+ await libjuju.deploy_charm(
+ application_name=charm_info.app_name,
+ path=charm_info.entity_url,
+ model_name=model_name,
+ channel=charm_info.channel,
+ )
+
+ @activity.defn(name=ACTIVITY_CHECK_CHARM_STATUS)
+ async def check_charm_status(self, check_charm_status: VduInstantiateInput) -> None:
+ """Validates the credentials by attempting to connect to the given Juju Controller.
+
+ Collaborators:
+ DB Read: vim_accounts
+ 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 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.
+ """
+ pass
+
class VimDbActivity:
"""Perform Database operations for VIM accounts.