Skip to content

Commit d4c3ce9

Browse files
committed
sandlock-oci: accept runc-compatible CLI flags from containerd shim
Signed-off-by: Cong Wang <cwang@multikernel.io>
1 parent 0262a71 commit d4c3ce9

1 file changed

Lines changed: 88 additions & 2 deletions

File tree

crates/sandlock-oci/src/main.rs

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ use clap::{Parser, Subcommand};
3434
use state::{SandboxState, Status};
3535
use std::path::PathBuf;
3636

37+
/// Format for the runc-compatible `--log` file. runc defaults to `text`; the
38+
/// containerd shim passes `json`.
39+
#[derive(Clone, Copy, Debug, PartialEq, Eq, clap::ValueEnum)]
40+
enum LogFormat {
41+
Text,
42+
Json,
43+
}
44+
3745
#[derive(Parser)]
3846
#[command(
3947
name = "sandlock-oci",
@@ -49,6 +57,29 @@ struct Cli {
4957
#[arg(long, global = true)]
5058
root: Option<PathBuf>,
5159

60+
/// Path to append fatal errors to (runc-compatible; read by the
61+
/// containerd shim to surface the failure reason).
62+
#[arg(long, global = true)]
63+
log: Option<PathBuf>,
64+
65+
/// Format for the --log file. runc defaults to "text"; the containerd
66+
/// shim passes "json".
67+
#[arg(long = "log-format", global = true, value_enum, default_value = "text")]
68+
log_format: LogFormat,
69+
70+
/// Accepted for runc compatibility; no-op (no logging framework yet).
71+
#[arg(long, global = true)]
72+
debug: bool,
73+
74+
/// Accepted for runc compatibility; ignored (sandlock is cgroup-less).
75+
#[arg(long = "systemd-cgroup", global = true)]
76+
systemd_cgroup: bool,
77+
78+
/// Accepted for runc compatibility; ignored. Both `--rootless` and
79+
/// `--rootless=true|false` are allowed.
80+
#[arg(long, global = true, num_args = 0..=1, require_equals = true, default_missing_value = "true")]
81+
rootless: Option<bool>,
82+
5283
#[command(subcommand)]
5384
command: Command,
5485
}
@@ -69,6 +100,12 @@ enum Command {
69100
/// Console socket path (ignored — sandlock doesn't use PTYs by default).
70101
#[arg(long = "console-socket")]
71102
console_socket: Option<PathBuf>,
103+
/// Accepted for runc compatibility; ignored (sandlock does not pivot_root).
104+
#[arg(long = "no-pivot")]
105+
no_pivot: bool,
106+
/// Accepted for runc compatibility; ignored (no session keyring).
107+
#[arg(long = "no-new-keyring")]
108+
no_new_keyring: bool,
72109
},
73110

74111
/// Start a previously created sandbox.
@@ -167,6 +204,12 @@ enum Command {
167204
/// OCI bundle path (accepted for runc compatibility; may be unused).
168205
#[arg(long = "bundle")]
169206
bundle: Option<String>,
207+
/// Accepted for runc compatibility; ignored (sandlock does not pivot_root).
208+
#[arg(long = "no-pivot")]
209+
no_pivot: bool,
210+
/// Accepted for runc compatibility; ignored (no session keyring).
211+
#[arg(long = "no-new-keyring")]
212+
no_new_keyring: bool,
170213
},
171214
}
172215

@@ -178,7 +221,7 @@ fn main() -> Result<()> {
178221
state::init_state_dir(cli.root.as_deref().and_then(|p| p.to_str()));
179222

180223
match cli.command {
181-
Command::Create { id, bundle, pid_file, console_socket: _ } => {
224+
Command::Create { id, bundle, pid_file, console_socket: _, no_pivot: _, no_new_keyring: _ } => {
182225
cmd_create(&id, &bundle, pid_file.as_deref())?;
183226
}
184227
Command::Start { id } => {
@@ -259,7 +302,7 @@ fn main() -> Result<()> {
259302
Command::Checkpoint { id, image_path } => {
260303
cmd_checkpoint(&id, &image_path)?;
261304
}
262-
Command::Restore { id, image_path, bundle: _ } => {
305+
Command::Restore { id, image_path, bundle: _, no_pivot: _, no_new_keyring: _ } => {
263306
cmd_restore(&id, &image_path)?;
264307
}
265308
}
@@ -868,6 +911,49 @@ fn parse_signal(s: &str) -> Result<i32> {
868911
#[cfg(test)]
869912
mod tests {
870913
use super::*;
914+
use clap::Parser;
915+
916+
#[test]
917+
fn accepts_runc_create_globals() {
918+
let cli = Cli::try_parse_from([
919+
"sandlock-oci", "--root", "/r", "--log", "/l", "--log-format", "json",
920+
"--systemd-cgroup", "--debug",
921+
"create", "--bundle", "/b", "--pid-file", "/p",
922+
"--no-pivot", "--no-new-keyring", "id",
923+
])
924+
.expect("should parse runc-style create invocation");
925+
assert!(matches!(cli.command, Command::Create { .. }));
926+
assert_eq!(cli.log.as_deref(), Some(std::path::Path::new("/l")));
927+
assert_eq!(cli.log_format, LogFormat::Json);
928+
}
929+
930+
#[test]
931+
fn accepts_globals_on_other_subcommands() {
932+
let subs: [&[&str]; 4] = [
933+
&["state", "id"],
934+
&["start", "id"],
935+
&["kill", "id", "SIGKILL"],
936+
&["delete", "--force", "id"],
937+
];
938+
for sub in subs {
939+
let mut argv = vec![
940+
"sandlock-oci", "--root", "/r", "--log", "/l",
941+
"--log-format", "json", "--systemd-cgroup",
942+
];
943+
argv.extend_from_slice(sub);
944+
Cli::try_parse_from(&argv)
945+
.unwrap_or_else(|e| panic!("failed to parse {:?}: {e}", argv));
946+
}
947+
}
948+
949+
#[test]
950+
fn rootless_both_forms_parse() {
951+
let bare = Cli::try_parse_from(["sandlock-oci", "--rootless", "list"]).unwrap();
952+
assert_eq!(bare.rootless, Some(true));
953+
let explicit =
954+
Cli::try_parse_from(["sandlock-oci", "--rootless=false", "list"]).unwrap();
955+
assert_eq!(explicit.rootless, Some(false));
956+
}
871957

872958
#[test]
873959
fn parse_signal_numeric() {

0 commit comments

Comments
 (0)