Bind prepared artifact selection against reclaim
This commit is contained in:
parent
d799cf4837
commit
1bd1d395d9
4 changed files with 209 additions and 21 deletions
|
|
@ -11,6 +11,7 @@ use lazaret_core::records::{
|
|||
Generation, GenerationIdentity, Participant, ParticipantOwnership, ParticipantRole,
|
||||
ParticipantState, PreparedArtifact,
|
||||
};
|
||||
use lazaret_linux::filesystem::SharedFileLock;
|
||||
use lazaret_linux::process::{ProcessOwnershipContext, current_process_identity};
|
||||
use lazaret_runtime_supervisor::sandbox::SandboxBundle;
|
||||
use lazaret_runtime_supervisor::supervision::RuntimeSupervisorLaunch;
|
||||
|
|
@ -65,6 +66,7 @@ pub struct BootstrapPlan<'a> {
|
|||
pub configuration: &'a ResolvedDomainConfiguration,
|
||||
pub generation_identity: GenerationIdentity,
|
||||
pub prepared_artifact: &'a PreparedArtifact,
|
||||
pub prepared_artifact_selection: Option<SharedFileLock>,
|
||||
pub state_anchor_layout: &'a StateAnchorLayout<'a>,
|
||||
pub runtime_launch: RuntimeSupervisorLaunch,
|
||||
pub sandbox_bundle: &'a SandboxBundle,
|
||||
|
|
@ -281,15 +283,21 @@ impl<'a> CoordinatorLifecycleAdapter<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn lease_prepared_lower(&self) -> Result<(), LifecycleServiceError> {
|
||||
fn lease_prepared_lower(&mut self) -> Result<(), LifecycleServiceError> {
|
||||
self.state_anchor()
|
||||
.begin_acquisition(
|
||||
self.plan.generation_identity.generation_id,
|
||||
self.plan.prepared_artifact,
|
||||
self.plan.state_anchor_layout,
|
||||
)
|
||||
.map(|_| ())
|
||||
.map_err(failure)
|
||||
.map_err(failure)?;
|
||||
drop(
|
||||
self.plan
|
||||
.prepared_artifact_selection
|
||||
.take()
|
||||
.ok_or_else(|| LifecycleServiceError("prepared artifact claim is absent".into()))?,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mount_state_anchor(&mut self) -> Result<(), LifecycleServiceError> {
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ fn run_private_client_bootstrap(arguments: &[OsString]) -> Result<(), PrivateCli
|
|||
.enable_all()
|
||||
.build()
|
||||
.map_err(failure)?;
|
||||
let selection = runtime
|
||||
let mut selection = runtime
|
||||
.block_on(select_runtime(
|
||||
&configuration,
|
||||
Arc::clone(&store),
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use lazaret_core::records::{
|
|||
Generation, GenerationIdentity, HostProcessOwnershipSlot, PreparedArtifact, Session,
|
||||
};
|
||||
use lazaret_ignored_workspace::git_common_directory;
|
||||
use lazaret_linux::filesystem::SharedFileLock;
|
||||
use lazaret_linux::filesystem::{RegularFileMailbox, mount_identity, namespace_identity};
|
||||
use lazaret_linux::process::{
|
||||
ProcessOwnershipContext, TargetCommand, child_broker, current_process_identity,
|
||||
|
|
@ -76,6 +77,7 @@ pub struct ColdStartInputs<'a> {
|
|||
pub generation: Generation,
|
||||
pub prepared_artifact: &'a PreparedArtifact,
|
||||
pub prepared_artifact_authority: &'a File,
|
||||
pub prepared_artifact_selection: SharedFileLock,
|
||||
pub prepared_artifact_label: &'a Path,
|
||||
pub root_process: RootProcess,
|
||||
pub container_id: ContainerId,
|
||||
|
|
@ -135,6 +137,7 @@ pub struct ColdStart<'a> {
|
|||
generation_identity: GenerationIdentity,
|
||||
prepared_artifact: &'a PreparedArtifact,
|
||||
state_anchor_layout: StateAnchorLayout<'a>,
|
||||
prepared_artifact_selection: Option<SharedFileLock>,
|
||||
runtime_launch: Option<RuntimeSupervisorLaunch>,
|
||||
sandbox_bundle: SandboxBundle,
|
||||
network_policy: lazaret_core::network::CanonicalDerivedNetworkPolicy,
|
||||
|
|
@ -256,6 +259,7 @@ impl<'a> ColdStart<'a> {
|
|||
generation_identity,
|
||||
prepared_artifact: inputs.prepared_artifact,
|
||||
state_anchor_layout,
|
||||
prepared_artifact_selection: Some(inputs.prepared_artifact_selection),
|
||||
runtime_launch: Some(runtime_launch),
|
||||
sandbox_bundle,
|
||||
network_policy,
|
||||
|
|
@ -371,6 +375,7 @@ impl<'a> ColdStart<'a> {
|
|||
configuration: self.configuration,
|
||||
generation_identity: self.generation_identity.clone(),
|
||||
prepared_artifact: self.prepared_artifact,
|
||||
prepared_artifact_selection: self.prepared_artifact_selection.take(),
|
||||
state_anchor_layout: &self.state_anchor_layout,
|
||||
runtime_launch: self
|
||||
.runtime_launch
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use lazaret_core::identity::{
|
|||
PrepareOperationId, SandboxId,
|
||||
};
|
||||
use lazaret_core::records::{DurableDecision, Generation, PreparedArtifact, VolumeKind};
|
||||
use lazaret_linux::filesystem::SharedFileLock;
|
||||
use lazaret_linux::platform::{PlatformObservation, check_platform};
|
||||
use lazaret_linux::user_namespace::UserNamespaceMap;
|
||||
use lazaret_prepared_lower::{
|
||||
|
|
@ -32,6 +33,8 @@ use crate::prepared_worker::prepare_in_user_namespace;
|
|||
use crate::recovery::recover_before_cold_start;
|
||||
use crate::sandbox_init::PRIVATE_SANDBOX_INIT_ROLE;
|
||||
|
||||
const PREPARED_SELECTION_ATTEMPTS: usize = 16;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RuntimeSelectionError {
|
||||
PreparedLower(PreparedLowerError),
|
||||
|
|
@ -78,6 +81,7 @@ pub struct RuntimeSelection {
|
|||
catalog: Catalog,
|
||||
artifact: PreparedArtifact,
|
||||
artifact_authority: File,
|
||||
artifact_selection: Option<SharedFileLock>,
|
||||
artifact_label: PathBuf,
|
||||
generation: Generation,
|
||||
container_id: ContainerId,
|
||||
|
|
@ -92,7 +96,7 @@ impl RuntimeSelection {
|
|||
/// # Errors
|
||||
/// Refuses a configuration other than the exact one used for selection.
|
||||
pub fn cold_start_inputs<'a>(
|
||||
&'a self,
|
||||
&'a mut self,
|
||||
configuration: &'a ResolvedDomainConfiguration,
|
||||
) -> Result<ColdStartInputs<'a>, RuntimeSelectionError> {
|
||||
if configuration.domain_id() != self.domain_id
|
||||
|
|
@ -107,6 +111,10 @@ impl RuntimeSelection {
|
|||
generation: self.generation.clone(),
|
||||
prepared_artifact: &self.artifact,
|
||||
prepared_artifact_authority: &self.artifact_authority,
|
||||
prepared_artifact_selection: self
|
||||
.artifact_selection
|
||||
.take()
|
||||
.ok_or_else(|| failure("selected artifact claim was already consumed"))?,
|
||||
prepared_artifact_label: &self.artifact_label,
|
||||
root_process: RootProcess::new(
|
||||
SANDBOX_INIT_DESTINATION,
|
||||
|
|
@ -174,17 +182,27 @@ async fn select_runtime_for_platform(
|
|||
)
|
||||
.await
|
||||
.map_err(RuntimeSelectionError::PreparedLower)?;
|
||||
let artifact = prepare_in_user_namespace(
|
||||
configuration,
|
||||
&image,
|
||||
PrepareOperationId::new(random_id()?),
|
||||
prepared_destinations(configuration),
|
||||
&user_namespace_map,
|
||||
)
|
||||
.map_err(|error| failure(format!("mapped preparation worker failed: {error}")))?;
|
||||
let artifact_authority = prepared
|
||||
.open_artifact_authority(&artifact)
|
||||
.map_err(RuntimeSelectionError::PreparedLower)?;
|
||||
let mut selection = None;
|
||||
for _ in 0..PREPARED_SELECTION_ATTEMPTS {
|
||||
let artifact = prepare_in_user_namespace(
|
||||
configuration,
|
||||
&image,
|
||||
PrepareOperationId::new(random_id()?),
|
||||
prepared_destinations(configuration),
|
||||
&user_namespace_map,
|
||||
)
|
||||
.map_err(|error| failure(format!("mapped preparation worker failed: {error}")))?;
|
||||
if let Some(selected) = prepared
|
||||
.select_artifact(&artifact)
|
||||
.map_err(RuntimeSelectionError::PreparedLower)?
|
||||
{
|
||||
selection = Some(selected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let selection = selection
|
||||
.ok_or_else(|| failure("prepared artifact was repeatedly reclaimed before selection"))?;
|
||||
let (artifact, artifact_authority, artifact_selection) = selection.into_parts();
|
||||
let artifact_label = PathBuf::from(std::ffi::OsString::from_vec(
|
||||
configuration
|
||||
.storage_root()
|
||||
|
|
@ -218,6 +236,7 @@ async fn select_runtime_for_platform(
|
|||
catalog,
|
||||
artifact,
|
||||
artifact_authority,
|
||||
artifact_selection: Some(artifact_selection),
|
||||
artifact_label,
|
||||
generation,
|
||||
container_id: ContainerId::new(random_id()?),
|
||||
|
|
|
|||
Loading…
Reference in a new issue