a3s-box-runtime 3.1.0

MicroVM runtime engine — VM lifecycle, OCI images, attestation, networking
Documentation
use a3s_box_core::{ExecutionLease, ExecutionManagerError, ExecutionManagerResult, ExecutionState};

use super::record::{execution_id, lease_from_record};
use super::store::RuntimeUpdate;
use super::support::{managed_state, required_handle};
use super::{BoxRecord, LocalExecutionManager, ManagedExecutionState};

impl LocalExecutionManager {
    pub(super) async fn ensure_started(
        &self,
        record: BoxRecord,
    ) -> ExecutionManagerResult<ExecutionLease> {
        super::record::validate_record_health(&record)?;
        match managed_state(&record)? {
            state @ (ManagedExecutionState::Creating | ManagedExecutionState::Created) => {
                self.claim_and_start(record, state).await
            }
            ManagedExecutionState::Starting => {
                let execution_id = execution_id(&record)?;
                match self.backend.inspect(&record).await {
                    Ok(observation) => {
                        observation.validate(&execution_id)?;
                        match observation.state {
                            ExecutionState::Running => {
                                let handle = required_handle(&observation, &execution_id)?;
                                let running = self
                                    .complete_with_handle(
                                        &record,
                                        ManagedExecutionState::Starting,
                                        ManagedExecutionState::Running,
                                        handle,
                                    )
                                    .await?;
                                lease_from_record(&running)
                            }
                            ExecutionState::Creating => Err(ExecutionManagerError::Unavailable(
                                format!("execution {execution_id} is still starting"),
                            )),
                            ExecutionState::Created => {
                                Err(ExecutionManagerError::Internal(format!(
                                    "backend reported created state while starting {execution_id}"
                                )))
                            }
                            ExecutionState::Stopped | ExecutionState::Failed => {
                                self.transition(
                                    &record,
                                    ManagedExecutionState::Starting,
                                    ManagedExecutionState::Failed,
                                    RuntimeUpdate::Terminal(observation.exit_code),
                                )
                                .await?;
                                Err(ExecutionManagerError::Conflict {
                                    execution_id: execution_id.clone(),
                                    message: "the reserved creation operation is terminal"
                                        .to_string(),
                                })
                            }
                            ExecutionState::Paused => Err(ExecutionManagerError::Internal(
                                format!("execution {execution_id} became paused while starting"),
                            )),
                        }
                    }
                    Err(ExecutionManagerError::NotFound(_)) => {
                        Err(ExecutionManagerError::Unavailable(format!(
                            "execution {execution_id} has been claimed for startup"
                        )))
                    }
                    Err(error) => Err(error),
                }
            }
            ManagedExecutionState::Running => lease_from_record(&record),
            state => Err(ExecutionManagerError::Conflict {
                execution_id: execution_id(&record)?,
                message: format!("creation operation is {state}"),
            }),
        }
    }

    pub(super) async fn claim_and_start(
        &self,
        record: BoxRecord,
        expected_state: ManagedExecutionState,
    ) -> ExecutionManagerResult<ExecutionLease> {
        super::record::validate_record_health(&record)?;
        let claimed = match self
            .transition(
                &record,
                expected_state,
                ManagedExecutionState::Starting,
                RuntimeUpdate::None,
            )
            .await
        {
            Ok(claimed) => claimed,
            Err(ExecutionManagerError::Conflict { .. }) => {
                let id = execution_id(&record)?;
                let current = self
                    .get(&id)
                    .await?
                    .ok_or_else(|| ExecutionManagerError::NotFound(id.clone()))?;
                return self.ensure_started_after_lost_claim(current).await;
            }
            Err(error) => return Err(error),
        };

        let execution_id = execution_id(&claimed)?;
        match self.backend.start(&claimed).await {
            Ok(handle) => {
                handle.validate(&execution_id)?;
                let running = self
                    .complete_with_handle(
                        &claimed,
                        ManagedExecutionState::Starting,
                        ManagedExecutionState::Running,
                        handle,
                    )
                    .await?;
                lease_from_record(&running)
            }
            Err(error) => self.resolve_start_error(claimed, error).await,
        }
    }

    async fn ensure_started_after_lost_claim(
        &self,
        record: BoxRecord,
    ) -> ExecutionManagerResult<ExecutionLease> {
        match managed_state(&record)? {
            ManagedExecutionState::Running => lease_from_record(&record),
            ManagedExecutionState::Creating | ManagedExecutionState::Created => {
                Err(ExecutionManagerError::Unavailable(format!(
                    "execution {} startup claim was released; retry the request",
                    execution_id(&record)?
                )))
            }
            ManagedExecutionState::Starting => {
                let id = execution_id(&record)?;
                match self.backend.inspect(&record).await {
                    Ok(observation) if observation.state == ExecutionState::Running => {
                        observation.validate(&id)?;
                        let running = self
                            .complete_with_handle(
                                &record,
                                ManagedExecutionState::Starting,
                                ManagedExecutionState::Running,
                                required_handle(&observation, &id)?,
                            )
                            .await?;
                        lease_from_record(&running)
                    }
                    Ok(_) | Err(ExecutionManagerError::NotFound(_)) => {
                        Err(ExecutionManagerError::Unavailable(format!(
                            "execution {id} startup is owned by another caller"
                        )))
                    }
                    Err(error) => Err(error),
                }
            }
            state => Err(ExecutionManagerError::Conflict {
                execution_id: execution_id(&record)?,
                message: format!("creation claim moved to {state}"),
            }),
        }
    }

    async fn resolve_start_error(
        &self,
        claimed: BoxRecord,
        start_error: ExecutionManagerError,
    ) -> ExecutionManagerResult<ExecutionLease> {
        let id = execution_id(&claimed)?;
        match self.backend.inspect(&claimed).await {
            Ok(observation) => {
                observation.validate(&id)?;
                match observation.state {
                    ExecutionState::Running => {
                        let running = self
                            .complete_with_handle(
                                &claimed,
                                ManagedExecutionState::Starting,
                                ManagedExecutionState::Running,
                                required_handle(&observation, &id)?,
                            )
                            .await?;
                        lease_from_record(&running)
                    }
                    ExecutionState::Stopped | ExecutionState::Failed => {
                        let _ = self
                            .transition(
                                &claimed,
                                ManagedExecutionState::Starting,
                                ManagedExecutionState::Failed,
                                RuntimeUpdate::Terminal(observation.exit_code),
                            )
                            .await;
                        Err(start_error)
                    }
                    ExecutionState::Created | ExecutionState::Creating | ExecutionState::Paused => {
                        Err(start_error)
                    }
                }
            }
            Err(ExecutionManagerError::NotFound(_)) => {
                let _ = self
                    .transition(
                        &claimed,
                        ManagedExecutionState::Starting,
                        ManagedExecutionState::Failed,
                        RuntimeUpdate::Terminal(None),
                    )
                    .await;
                Err(start_error)
            }
            Err(_) => Err(start_error),
        }
    }
}