Make Git router teardown process-bounded

This commit is contained in:
ms2k 2026-07-19 23:34:06 +09:00
commit e60baad993

View file

@ -1,15 +1,17 @@
use super::{
Arc, AwaitingAttachedRunsc, BENCHMARK_GUEST, BTreeMap, BundleDigest, CommittedSandboxRuntime,
ConfigurationLoadRequest, ContainerId, CoordinatorId, Domain, DomainStoreMutation,
DurableDecision, Generation, GenerationId, HostCoordinatorDomainStore,
HostProcessOwnershipSlot, Ipv4Addr, MatrixError, NETWORK_NAMESPACE_PATH, NetworkCoordinator,
NetworkSidecarId, Path, PathBuf, ProcessOwnershipContext, ResolvedDomainConfiguration,
RootProcess, RunscCommand, RuntimeNetworkLaunch, RuntimeSupervisorLaunch, SandboxBuildRequest,
SandboxBundle, SandboxCoordinator, SandboxId, SocketAddr, SocketAddrExt, TcpListener, TempDir,
UnixListener, UserNamespaceMap, build_sandbox_bundle, current_mount_identity,
current_process_identity, default_sandbox_layout, derive_ipv4_policy, failure, fs, hex,
host_path, load_trusted_configuration, lock_file, stage_benchmark_rootfs_and_control,
stage_rootfs_and_control, try_exclusive_flock,
DurableDecision, File, Generation, GenerationId, GitRoutingCoordinator,
HostCoordinatorDomainStore, HostPath, HostProcessOwnershipSlot, Ipv4Addr, MatrixError,
NETWORK_NAMESPACE_PATH, NetworkCoordinator, NetworkSidecarId, Path, PathBuf,
ProcessOwnershipContext, ResolvedDomainConfiguration, RootProcess, RunscCommand,
RuntimeGitRoutingAuthority, RuntimeGitRoutingLaunch, RuntimeNetworkLaunch,
RuntimeSupervisorLaunch, SandboxBuildRequest, SandboxBundle, SandboxCoordinator, SandboxId,
SocketAddr, SocketAddrExt, TargetCommand, TcpListener, TempDir, UnixListener, UserNamespaceMap,
build_sandbox_bundle, build_sandbox_bundle_with_workspace, child_broker,
current_mount_identity, current_process_identity, default_sandbox_layout, derive_ipv4_policy,
failure, fs, hex, host_path, load_trusted_configuration, lock_file,
stage_benchmark_rootfs_and_control, stage_rootfs_and_control, try_exclusive_flock,
};
pub(super) struct Fixture {
@ -19,17 +21,24 @@ pub(super) struct Fixture {
pub(super) bundle: SandboxBundle,
pub(super) activity: PathBuf,
pub(super) benchmark_results: Option<PathBuf>,
git_routing: Option<GitRoutingFixture>,
}
impl Fixture {
pub(super) fn new() -> Result<Self, MatrixError> {
let tree = tempfile::tempdir()?;
let root = tree.path().to_path_buf();
Self::build(&root, Some(tree))
Self::build(&root, Some(tree), false)
}
pub(super) fn new_git_routed() -> Result<Self, MatrixError> {
let tree = tempfile::tempdir()?;
let root = tree.path().to_path_buf();
Self::build(&root, Some(tree), true)
}
pub(super) fn in_directory(root: &Path) -> Result<Self, MatrixError> {
Self::build(root, None)
Self::build(root, None, false)
}
#[allow(clippy::too_many_arguments)]
@ -136,16 +145,24 @@ impl Fixture {
bundle,
workspace.join("activity"),
Some(results),
None,
)
}
fn build(root: &Path, tree: Option<TempDir>) -> Result<Self, MatrixError> {
fn build(
root: &Path,
tree: Option<TempDir>,
route_git_workspace: bool,
) -> Result<Self, MatrixError> {
let configuration_directory = root.join("configuration");
let workspace = root.join("workspace");
let runtime = root.join("runtime");
fs::create_dir(&configuration_directory)?;
fs::create_dir(&workspace)?;
fs::create_dir(&runtime)?;
let git_routing = route_git_workspace
.then(|| GitRoutingFixture::create(root, &workspace))
.transpose()?;
let configuration_path = configuration_directory.join("lazaret.toml");
fs::write(
&configuration_path,
@ -180,14 +197,20 @@ impl Fixture {
.map_err(failure)?;
let namespace =
lazaret_linux::filesystem::namespace_identity(Path::new(NETWORK_NAMESPACE_PATH))?;
let bundle = build_sandbox_bundle(SandboxBuildRequest {
let request = SandboxBuildRequest {
configuration: &configuration,
container_id,
expected_network_namespace: namespace,
root_process,
terminal: None,
prepared_root: runtime_domain.join("prepared-root"),
})
};
let bundle = match &git_routing {
Some(git_routing) => {
build_sandbox_bundle_with_workspace(request, git_routing.mountpoint.clone())
}
None => build_sandbox_bundle(request),
}
.map_err(failure)?;
Self::finish_build(
tree,
@ -195,6 +218,7 @@ impl Fixture {
bundle,
workspace.join("activity"),
None,
git_routing,
)
}
@ -204,6 +228,7 @@ impl Fixture {
bundle: SandboxBundle,
activity: PathBuf,
benchmark_results: Option<PathBuf>,
git_routing: Option<GitRoutingFixture>,
) -> Result<Self, MatrixError> {
let runtime_domain = host_path(configuration.runtime_domain_root().canonical_label());
let container_id = ContainerId::new([6; 32]);
@ -252,6 +277,7 @@ impl Fixture {
bundle,
activity,
benchmark_results,
git_routing,
})
}
@ -263,7 +289,7 @@ impl Fixture {
&self,
command: &RunscCommand,
) -> Result<AwaitingAttachedRunsc, MatrixError> {
let launch = RuntimeSupervisorLaunch::from_runsc_command(
let mut launch = RuntimeSupervisorLaunch::from_runsc_command(
ProcessOwnershipContext {
domain_id: self.configuration.domain_id(),
generation_id: GenerationId::new(7),
@ -271,10 +297,40 @@ impl Fixture {
slot: lazaret_core::records::HostProcessOwnershipSlot::SandboxRuntimeSupervisor,
},
command,
)?
.with_user_namespace_map(UserNamespaceMap::resolve_current().map_err(failure)?)?;
AwaitingAttachedRunsc::launch(&SandboxCoordinator::new(&self.store), &launch)
.map_err(failure)
)?;
if let Some(git_routing) = &self.git_routing {
launch = launch.with_git_routing(git_routing.launch()?)?;
}
launch = launch
.with_user_namespace_map(UserNamespaceMap::resolve_current().map_err(failure)?)?;
let mut pending =
AwaitingAttachedRunsc::launch(&SandboxCoordinator::new(&self.store), &launch)
.map_err(failure)?;
if let Some(git_routing) = &self.git_routing {
let coordinator = GitRoutingCoordinator::new(&self.store);
coordinator
.begin_intent(
GenerationId::new(7),
HostPath::new(
git_routing
.mountpoint
.as_os_str()
.as_encoded_bytes()
.to_vec(),
),
HostPath::new(
git_routing
.workspace
.as_os_str()
.as_encoded_bytes()
.to_vec(),
),
HostPath::new(git_routing.isolated.as_os_str().as_encoded_bytes().to_vec()),
)
.map_err(failure)?;
pending.start_git_routing(&coordinator).map_err(failure)?;
}
Ok(pending)
}
pub(super) fn alternate_bundle(&self) -> Result<SandboxBundle, MatrixError> {
@ -316,6 +372,68 @@ impl Fixture {
}
}
struct GitRoutingFixture {
workspace: PathBuf,
isolated: PathBuf,
mountpoint: PathBuf,
git_common: PathBuf,
transient_hooks: PathBuf,
transient_config: PathBuf,
}
impl GitRoutingFixture {
fn create(root: &Path, workspace: &Path) -> Result<Self, MatrixError> {
child_broker()
.run_transient(
&TargetCommand::new("git")
.argument("init")
.argument("--quiet")
.argument("--initial-branch=main")
.argument(workspace),
)
.map_err(failure)?;
let routing = root.join("git-routing");
let isolated = routing.join("isolated");
let mountpoint = routing.join("workspace");
let transient_hooks = routing.join("hooks");
let transient_config = routing.join("config");
for directory in [&isolated, &mountpoint, &transient_hooks] {
fs::create_dir_all(directory)?;
}
fs::write(&transient_config, b"")?;
Ok(Self {
workspace: workspace.to_path_buf(),
isolated,
mountpoint,
git_common: workspace.join(".git"),
transient_hooks,
transient_config,
})
}
fn launch(&self) -> Result<RuntimeGitRoutingLaunch, MatrixError> {
RuntimeGitRoutingLaunch::new(RuntimeGitRoutingAuthority {
workspace: File::open(&self.workspace)?,
workspace_label: self.workspace.clone(),
isolated: File::open(&self.isolated)?,
mountpoint: File::open(&self.mountpoint)?,
mountpoint_label: self.mountpoint.clone(),
git_common: File::open(&self.git_common)?,
git_common_label: self.git_common.clone(),
transient_hooks: File::open(&self.transient_hooks)?,
transient_hooks_label: self.transient_hooks.clone(),
transient_config: File::options()
.read(true)
.write(true)
.open(&self.transient_config)?,
transient_config_label: self.transient_config.clone(),
global_excludes: None,
isolate_ignored: true,
})
.map_err(failure)
}
}
pub(super) struct NetworkFixture {
_tree: TempDir,
_host_loopback: TcpListener,