Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/build-rust-package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ let
'';

CODCHI_WSL_VERSION_MIN = "2.0.14";
CODCHI_WSL_VERSION_MAX = "2.4.8";
CODCHI_WSL_VERSION_MAX = "2.4.11";

};
linux = rec {
Expand Down
19 changes: 19 additions & 0 deletions codchi/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,25 @@ See the following docs on how to register the completions with your shell:
#[command(subcommand)]
#[clap(about = "Utilities for interacting with the `codchistore` container.")]
Store(StoreCmd),

/// Try to recover the file system of a code machine
#[clap(hide = true)]
#[cfg(target_os = "windows")]
Recover {
/// Name of the code machine
name: String,
},

/// Edit a file of a code machine without starting it.
#[clap(hide = true)]
#[cfg(target_os = "windows")]
Visudo {
/// Name of the code machine
name: String,

/// File to edit
file: String,
},
}

mod secrets {
Expand Down
38 changes: 27 additions & 11 deletions codchi/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,6 @@ Thank you kindly!"#
// preload config
let cfg = CodchiConfig::get();

if !matches!(cli.command, Some(Cmd::Tray {})) && cfg.tray.autostart {
thread::spawn(|| {
// prevent race condition when initializing codchistore
thread::sleep(Duration::from_millis(1000));
Driver::host()
.start_tray(false)
.trace_err("Failed starting codchi's tray")
.ignore();
});
}

// process commands without the store commands
match &cli.command {
Some(Cmd::Tar { name, target_file }) => {
Expand All @@ -119,9 +108,30 @@ Thank you kindly!"#
exit(0);
}
},
#[cfg(target_os = "windows")]
Some(Cmd::Visudo { name, file }) => {
Machine::by_name(name, false)?.visudo(&file.to_string())?;
exit(0);
}
#[cfg(target_os = "windows")]
Some(Cmd::Recover { name }) => {
platform::machine_recover(&name.to_string())?;
exit(0);
}
_ => {}
}

if !matches!(cli.command, Some(Cmd::Tray {})) && cfg.tray.autostart {
thread::spawn(|| {
// prevent race condition when initializing codchistore
thread::sleep(Duration::from_millis(1000));
Driver::host()
.start_tray(false)
.trace_err("Failed starting codchi's tray")
.ignore();
});
}

CLI_ARGS
.set(cli.clone())
.expect("Only main is allowed to set CLI_ARGS.");
Expand Down Expand Up @@ -364,6 +374,12 @@ secret. Is this OK? [y/n]",
Cmd::Tar { .. } => unreachable!(),

Cmd::Store(_) => unreachable!(),

#[cfg(target_os = "windows")]
Cmd::Visudo { .. } => unreachable!(),

#[cfg(target_os = "windows")]
Cmd::Recover { .. } => unreachable!(),
}
if CodchiConfig::get().tray.autostart {
Driver::host()
Expand Down
3 changes: 3 additions & 0 deletions codchi/src/platform/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ pub trait MachineDriver: Sized {

/// Duplicate the container backing this machine
fn duplicate_container(&self, target: &Machine) -> Result<()>;

/// Open the file without starting the machine
fn visudo(&self, file: &str) -> Result<()>;
}

#[derive(Debug, Clone)]
Expand Down
2 changes: 2 additions & 0 deletions codchi/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub use platform::store_debug_shell;

#[cfg(target_os = "windows")]
pub use platform::store_recover;
#[cfg(target_os = "windows")]
pub use platform::machine_recover;

#[cfg(target_os = "windows")]
pub use platform::start_wsl_vpnkit;
Expand Down
137 changes: 63 additions & 74 deletions codchi/src/platform/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::{
Driver, LinuxCommandTarget, LinuxUser, Machine, MachineDriver, NixDriver, PlatformStatus, Store,
};
use crate::progress_scope;
use crate::util::{with_tmp_file, LinuxPath, PathExt, ResultExt, UtilExt};
use crate::util::{try_n_times, with_tmp_file, LinuxPath, PathExt, ResultExt, UtilExt};
use crate::{
cli::DEBUG,
config::CodchiConfig,
Expand Down Expand Up @@ -140,30 +140,25 @@ daemonize -e /var/log/wsl-vpnkit -o /var/log/wsl-vpnkit /bin/nix run 'nixpkgs#ws
Ok(())
}

pub fn store_recover() -> Result<()> {
wsl::recover_instance(
consts::files::STORE_ROOTFS_NAME,
consts::CONTAINER_STORE_NAME,
)
}

pub fn machine_recover(machine_name: &str) -> Result<()> {
wsl::recover_instance(
consts::files::MACHINE_ROOTFS_NAME,
&machine::machine_name(machine_name),
)
}

pub fn stop_wsl_vpnkit(store: &impl Store) -> Result<()> {
store.cmd().run("pkill", &["wsl-vpnkit"]).wait_ok()?;
Ok(())
}

pub fn win_path_to_wsl(path: &PathBuf) -> anyhow::Result<LinuxPath> {
wsl_command()
.args([
"-d",
&consts::CONTAINER_STORE_NAME,
"--system",
"--user",
"root",
])
.args([
"wslpath",
"-u",
&path.display().to_string().replace("\\", "/"),
])
.output_utf8_ok()
.map(|path| LinuxPath(path.trim().to_owned()))
.with_context(|| format!("Failed to run 'wslpath' with path {path:?}."))
}

pub fn store_debug_shell() -> anyhow::Result<()> {
LinuxCommandDriver {
instance_name: consts::CONTAINER_STORE_NAME.to_string(),
Expand All @@ -173,53 +168,6 @@ pub fn store_debug_shell() -> anyhow::Result<()> {
Ok(())
}

pub fn store_recover() -> anyhow::Result<()> {
use wsl::extract_from_msix;

extract_from_msix(files::STORE_ROOTFS_NAME, |store_tar| {
let tar_from_wsl = win_path_to_wsl(store_tar)?;
extract_from_msix("busybox", |busybox| {
let busybox_from_wsl = win_path_to_wsl(busybox)?;
wsl_command()
.args([
"-d",
&consts::CONTAINER_STORE_NAME,
"--system",
"--user",
"root",
])
.args(["mount", "-o", "remount,rw", "/mnt/wslg/distro"])
.wait_ok()?;
wsl_command()
.args([
"-d",
&consts::CONTAINER_STORE_NAME,
"--system",
"--user",
"root",
])
.args([
&busybox_from_wsl.0,
"tar",
"-C",
"/mnt/wslg/distro",
"-xzf",
&tar_from_wsl.0,
])
.wait_ok()?;

let _ = wsl::wsl_command()
.arg("--terminate")
.arg(consts::CONTAINER_STORE_NAME)
.wait_ok()
.trace_err("Failed stopping store container");

log::info!("Restored file system of `codchistore`.");
Ok(())
})
})
}

impl MachineDriver for Machine {
fn cmd(&self) -> impl LinuxCommandTarget {
LinuxCommandDriver {
Expand Down Expand Up @@ -345,9 +293,23 @@ tail -f "{log_file}"
});

// Machine is started by issuing a command
self.cmd()
.script(r#"systemctl is-system-running | grep -E "running|degraded""#.to_string())
.retry_until_ok();
if let Err(e) = try_n_times(Duration::from_millis(500), 20, || {
self.cmd()
.script(r#"systemctl is-system-running | grep -E "running|degraded""#.to_string())
.wait_ok()
}) {
log::error!("{}", e);
log::error!("Failed starting machine. Trying to recover...");
machine_recover(&self.config.name)?;
try_n_times(Duration::from_millis(500), 20, || {
self.cmd()
.script(
r#"systemctl is-system-running | grep -E "running|degraded""#.to_string(),
)
.wait_ok()
})
.with_context(|| format!("Failed starting WSL instance..."))?;
}

cancel_tx
.send(())
Expand Down Expand Up @@ -416,7 +378,7 @@ tail -f "{log_file}"
let mut cmd = wsl_command();
cmd.args([
"-d",
&consts::machine::machine_name(&self.config.name),
&machine::machine_name(&self.config.name),
"--system",
"--user",
"root",
Expand Down Expand Up @@ -466,7 +428,7 @@ tail -f "{log_file}"

self.write_env_file(etc_dir.join("codchi-env"))?;

let tmp_in_wsl = win_path_to_wsl(&tmp_dir)?;
let tmp_in_wsl = wsl::win_path_to_wsl(&tmp_dir)?;

wsl_cmd()
.args(["cp", "-r", &format!("{}/*", tmp_in_wsl.0), merged])
Expand All @@ -475,7 +437,7 @@ tail -f "{log_file}"
Ok(())
})?;

let wsl_path = win_path_to_wsl(&target_absolute)?;
let wsl_path = wsl::win_path_to_wsl(&target_absolute)?;
wsl_cmd()
.args([
"/mnt/wslg/distro/bin/tar",
Expand Down Expand Up @@ -513,7 +475,7 @@ tail -f "{log_file}"
}

fn duplicate_container(&self, target: &Machine) -> Result<()> {
let target_name = consts::machine::machine_name(&target.config.name);
let target_name = machine::machine_name(&target.config.name);
if Self::read_platform_status(&self.config.name)? == PlatformStatus::Running {
if io::stdin().is_terminal()
&& inquire::Confirm::new(&format!(
Expand Down Expand Up @@ -556,6 +518,33 @@ state. Is this OK? [y/n]",
}
Ok(())
}

fn visudo(&self, file: &str) -> Result<()> {
wsl_command()
.args([
"-d",
&machine::machine_name(&self.config.name),
"--system",
"--user",
"root",
])
.args(["mount", "-o", "remount,rw", "/mnt/wslg/distro"])
.wait_ok()?;
wsl_command()
.args([
"-d",
&machine::machine_name(&self.config.name),
"--cd",
"/mnt/wslg/distro",
"--system",
"--user",
"root",
])
.args(["./bin/vi", &format!("./{file}")])
.wait_inherit()?;

Ok(())
}
}

#[derive(Debug, Clone)]
Expand Down
66 changes: 66 additions & 0 deletions codchi/src/platform/windows/wsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,69 @@ impl LinuxPath {
.join(self.0.clone())
}
}

pub fn win_path_to_wsl(path: &PathBuf) -> anyhow::Result<LinuxPath> {
wsl_command()
.args([
"-d",
&consts::CONTAINER_STORE_NAME,
"--system",
"--user",
"root",
])
.args([
"wslpath",
"-u",
&path.display().to_string().replace("\\", "/"),
])
.output_utf8_ok()
.map(|path| LinuxPath(path.trim().to_owned()))
.with_context(|| format!("Failed to run 'wslpath' with path {path:?}."))
}


pub fn recover_instance(rootfs: &str, instance_name: &str) -> anyhow::Result<()> {
extract_from_msix(rootfs, |rootfs_tar| {
let tar_from_wsl = win_path_to_wsl(rootfs_tar)?;
extract_from_msix("busybox", |busybox| {
let busybox_from_wsl = win_path_to_wsl(busybox)?;
wsl_command()
.args([
"-d",
instance_name,
"--system",
"--user",
"root",
])
.args(["mount", "-o", "remount,rw", "/mnt/wslg/distro"])
.wait_ok()?;
wsl_command()
.args([
"-d",
instance_name,
"--system",
"--user",
"root",
])
.args([
&busybox_from_wsl.0,
"tar",
"-C",
"/mnt/wslg/distro",
"-xzf",
&tar_from_wsl.0,
])
.wait_ok()?;

let _ = wsl_command()
.arg("--terminate")
.arg(instance_name)
.wait_ok()
.trace_err("Failed stopping WSL instance");

log::info!("Restored file system of `{instance_name}`.");
Ok(())
})
})
}

2 changes: 1 addition & 1 deletion codchi/src/tray/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ pub fn run() -> Result<()> {
settings.push(mk_checkbox(
"Isolate the network of each code machine (requires restarting machines)",
|config| config.enable_wsl_netns,
|cfg, enabled| cfg.enable_wsl_vpnkit(enabled),
|cfg, enabled| cfg.enable_wsl_netns(enabled),
));
settings.push(mk_checkbox(
"Enable wsl-vpnkit",
Expand Down
Loading
Loading