Skip to content

Commit

Permalink
Add runc config/state/cli parser
Browse files Browse the repository at this point in the history
  • Loading branch information
nbdd0121 committed Apr 23, 2024
1 parent 76e0cd0 commit 19a489c
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/runc/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use std::path::PathBuf;

use clap::ValueEnum;
use once_cell::sync::Lazy;

#[derive(ValueEnum, Clone, Copy, PartialEq, Eq)]
pub enum LogFormat {
Json,
Text,
}

/// runc command line.
#[derive(clap::Parser)]
pub struct Command {
#[command(flatten)]
pub global: GlobalOptions,

#[command(subcommand)]
pub command: Subcommand,
}

#[derive(clap::Args)]
pub struct GlobalOptions {
#[arg(long)]
pub debug: bool,

#[arg(long)]
pub log: Option<PathBuf>,

#[arg(long, default_value = "text")]
pub log_format: LogFormat,

#[arg(long, default_value = "/run/runc")]
pub root: PathBuf,

#[arg(long)]
pub systemd_cgroup: bool,
}

#[derive(clap::Subcommand)]
pub enum Subcommand {
// We only care about the `create` subcommand.
// We need to be able to parse the rest (hence `trailing_var_arg` and `external_subcommand`) without error, but
// we don't make use of these and forward to runc directly.
Create(CreateOptions),
Run {
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<String>,
},
#[command(external_subcommand)]
#[allow(unused)]
Other(Vec<String>),
}

static BUNDLE_DEFAULT: Lazy<PathBuf> = Lazy::new(|| std::env::current_dir().unwrap());

#[derive(clap::Args)]
pub struct CreateOptions {
#[arg(short, long, default_value = BUNDLE_DEFAULT.as_os_str())]
pub bundle: PathBuf,

#[arg(long)]
pub console_socket: Option<PathBuf>,

#[arg(long)]
pub pid_file: Option<PathBuf>,

pub container_id: String,
}
45 changes: 45 additions & 0 deletions src/runc/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::collections::HashMap;
use std::path::Path;

use anyhow::{Context, Result};
use serde::Deserialize;

#[non_exhaustive]
#[derive(Debug, Deserialize)]
pub struct User {
pub uid: u32,
pub gid: u32,
}

#[non_exhaustive]
#[derive(Debug, Deserialize)]
pub struct Process {
pub user: User,
}

/// OCI config.
///
/// Only config that we need are implemented here.
/// Ref: https://github.com/opencontainers/runtime-spec/blob/main/config.md
#[non_exhaustive]
#[derive(Debug, Deserialize)]
pub struct Config {
pub process: Process,
#[serde(default)]
pub annotations: HashMap<String, String>,
}

impl Config {
pub fn from_str(s: &str) -> Result<Self> {
serde_json::from_str(s).context("Cannot parse config.json")
}

pub fn from_config(path: &Path) -> Result<Self> {
Self::from_str(&std::fs::read_to_string(path).context("Cannot read config.json")?)
}

pub fn from_bundle(bundle: &Path) -> Result<Self> {
let config = bundle.join("config.json");
Self::from_config(&config)
}
}
3 changes: 3 additions & 0 deletions src/runc/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
pub mod cli;
pub mod config;
pub mod log;
pub mod state;
37 changes: 37 additions & 0 deletions src/runc/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use std::path::{Path, PathBuf};

use anyhow::{Context, Result};
use serde::Deserialize;

#[non_exhaustive]
#[derive(Debug, Deserialize)]
pub struct CgroupPaths {
#[serde(rename = "")]
pub unified: PathBuf,
pub devices: Option<PathBuf>,
}

/// runc `libcontainer` states.
///
/// Only states that we need are implemented here.
/// Ref: https://github.com/opencontainers/runc/blob/6a2813f16ad4e3be44903f6fb499c02837530ad5/libcontainer/container_linux.go#L52
#[non_exhaustive]
#[derive(Debug, Deserialize)]
pub struct State {
pub init_process_pid: u32,
pub cgroup_paths: CgroupPaths,
}

impl State {
pub fn from_str(s: &str) -> Result<Self> {
serde_json::from_str(s).context("Cannot parse state.json")
}

pub fn from_state(path: &Path) -> Result<Self> {
Self::from_str(&std::fs::read_to_string(path).context("Cannot read state.json")?)
}

pub fn from_root_and_id(root: &Path, id: &str) -> Result<Self> {
Self::from_state(&root.join(format!("{}/state.json", id)))
}
}

0 comments on commit 19a489c

Please sign in to comment.