初步完成

main
阳光少年 1 year ago
commit 8d8939624b

363
Cargo.lock generated

@ -0,0 +1,363 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "anstyle-parse"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "clap"
version = "4.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "nix"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rocker"
version = "0.1.0"
dependencies = [
"clap",
"nix",
"serde",
"serde_json",
"toml",
"uuid",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
dependencies = [
"getrandom",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

@ -0,0 +1,12 @@
[package]
name = "rocker"
version = "0.1.0"
edition = "2021"
[dependencies]
uuid = {version = "1.3", features = ["v4"]}
toml = "0.5"
clap = {version = "4.5.0", features = ["derive"]}
nix = {version = "0.29", features = ["sched", "process", "hostname", "mount", "fs", "env", "user", "term"]}
serde = { version = "1.0", features = ["derive"] }
toml = "0.8"

@ -0,0 +1,23 @@
WORKSPACE := /root/rocker
build:
cargo build --release
# 创建WORKSPACE 对应的文件夹
install: build
mkdir -p $(WORKSPACE)
mkdir -p $(WORKSPACE)/images
mkdir -p $(WORKSPACE)/volumes
mkdir -p $(WORKSPACE)/containers
chmod -R 777 $(WORKSPACE)
cp images/* /root/rocker/images/
cp target/release/rocker /usr/bin/rocker
# 创建一个普通用户
-useradd -g rocker rocker
-groupadd rocker
clean:
rm -rf $(WORKSPACE)
rm -rf /usr/bin/rocker

Binary file not shown.

@ -0,0 +1,45 @@
use std::{error::Error, fmt::{Debug, Display, Formatter}};
use nix::errno::Errno;
pub type Result<T> = std::result::Result<T, RockerError>;
#[derive(Debug)]
pub enum RockerError {
IoError(std::io::Error),
OtherError(String),
ErrnoError(Errno)
}
impl Display for RockerError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::IoError(e) => write!(f, "{}", e),
Self::OtherError(s) => write!(f, "{}", s),
Self::ErrnoError(e) => write!(f, "{}", e)
}
}
}
impl Error for RockerError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::IoError(e) => Some(e),
Self::OtherError(_) => None,
Self::ErrnoError(e) => Some(e)
}
}
}
impl From<std::io::Error> for RockerError {
fn from(value: std::io::Error) -> Self {
Self::IoError(value)
}
}
impl From<Errno> for RockerError {
fn from(err: Errno) -> Self {
Self::OtherError(format!("errno: {err}"))
}
}

@ -0,0 +1,311 @@
use std::arch::asm;
use std::ffi::{CStr, CString};
use std::fs::File;
use std::os::fd::AsRawFd;
use std::os::unix::fs::PermissionsExt;
use nix::libc::{setgid, CLONE_NEWCGROUP, MS_NODEV, MS_NOSUID};
use nix::sched::{clone, CloneCb, CloneFlags};
use nix::sys::wait::{wait, waitpid, waitid, WaitPidFlag};
use nix::unistd::{chdir, chroot, dup2, execv, pivot_root, setuid, sleep, Gid, Pid, Uid, User, setgroups};
use nix::mount::{mount, MntFlags, MsFlags, umount2, umount};
use nix::env::clearenv;
use nix::pty;
use serde::Deserialize;
use std::path::{Path, PathBuf};
use clap::Parser;
use error::{Result, RockerError};
mod error;
use uuid;
use std::{io, fs};
use toml;
use serde::Deserialize;
static WORKSPACE: &str = "/root/rocker";
static USER_NAME: &str = "rocker";
static mut STACK: [u8; 1024*1024*1] = [0; 1024*1024*1];
static CLONE_FLAG: i32 = 0b1101100000000100000000000000000; // CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNET;
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct RockerArgs {
// --wait/--log --run /bin/bash --image busybox
#[arg(long)]
run: Option<String>,
#[arg(long)]
image: Option<String>,
#[arg(long)]
log: bool,
#[arg(long)]
wait: bool,
}
/// 从images解压到volumes
fn extend_image(image_name: &String) -> Result<(PathBuf)> {
// volumes只读层
let volume_path = Path::new(WORKSPACE).join("volumes").join(image_name);
if volume_path.exists() {
return Ok(volume_path);
} else {
// std::fs::create_dir_all(&volume_path)?;
// std::fs::set_permissions(&volume_path, PermissionsExt::from_mode(0o777))?;
create_dir_and_set777(&volume_path)?;
}
let volume_path_str = volume_path.to_str().unwrap(); // 安全的unwrap
// 源文件
let image_path = Path::new(WORKSPACE).join("images").join(image_name);
if image_path.exists() == false {
return Err(RockerError::from(io::Error::new(io::ErrorKind::NotFound, "未找到镜像")));
}
let image_path_str = image_path.to_str().unwrap(); // 安全的unwrap
// 解压缩
let out = std::process::Command::new("tar")
.arg("-xvf")
.arg(image_path_str)
.arg("-C")
.arg(volume_path_str)
.output()?;
let std_out = String::from_utf8_lossy(&out.stdout);
let std_err = String::from_utf8_lossy(&out.stderr);
if std_err.len() == 0 {
println!("解压缩完毕: {std_out:?}");
} else {
return Err(RockerError::from(io::Error::new(io::ErrorKind::Other, format!("解压缩镜像失败: {std_err}"))));
}
Ok(volume_path)
}
fn init_container_overlay<P: AsRef<Path>>(volume_path: P, upper_path: P, merged_path: P) -> Result<()> {
let lower_dir = volume_path.as_ref().to_string_lossy().to_string();
let upper_dir = upper_path.as_ref().to_string_lossy().to_string();
let merged_dir = merged_path.as_ref().to_string_lossy().to_string();
let dirs = format!("lowerdir={lower_dir},upperdir={upper_dir},workdir={merged_dir}");
println!("dirs: {dirs:?}");
let out = std::process::Command::new("mount")
.arg("-t")
.arg("overlay")
.arg("overlay")
.arg("-o")
.arg(dirs)
.arg(merged_dir)
.output()?;
let std_out = String::from_utf8_lossy(&out.stdout);
let std_err = String::from_utf8_lossy(&out.stderr);
if std_err.len() == 0 {
println!("容器文件系统创建完成: {std_out:?}");
} else {
return Err(RockerError::from(io::Error::new(io::ErrorKind::Other, format!("容器文件系统创建失败: {std_err:?}"))));
}
Ok(())
}
fn init_container_pivot<P: AsRef<Path>>(merged_path: P) -> Result<()> {
// 在我们没有设置 chroot之前, 需要先把所有挂载点的传播类型改为 private, 避免进程中的系统调用污染全局
mount(None::<&str>, "/", None::<&str>, MsFlags::MS_PRIVATE | MsFlags::MS_REC, None::<&str>)?;
// 修改overlayfs 为rootfs
chdir(merged_path.as_ref())?;
let pwd_path = std::env::current_dir()?;
let pwd_str = pwd_path.to_string_lossy().to_string();
// 挂载bind
mount(Some(pwd_str.as_str()), pwd_str.as_str(), Some("bind"), MsFlags::MS_BIND | MsFlags::MS_REC, Some(""))?;
// 创建 rootfs/.pivot_root 目录用于存储 old_root
let pivot_root_dir = format!("{pwd_str}/.pivot_root");
// 将系统rootfs切换到新的rootfs, 并设置权限
std::fs::create_dir(&pivot_root_dir)?;
std::fs::set_permissions(&pivot_root_dir, PermissionsExt::from_mode(0o777))?;
pivot_root(pwd_str.as_str(), pivot_root_dir.as_str())?;
// 修改当前进程工作目录(注意我们之前已经到rootfs内, 并且把根目录设置完毕了)
chdir("/")?;
// 卸载 old_root, 并删除临时文件
umount2(".pivot_root", MntFlags::MNT_DETACH).unwrap();
std::fs::remove_dir(".pivot_root").unwrap();
Ok(())
}
fn init_container_mount() -> Result<()> {
// 挂载proc
let mount_flags = MsFlags::MS_NODEV | MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID;
mount(Some("proc"), "/proc", Some("proc"), mount_flags, Some(""))?;
// 挂载dev
mount(Some("tmpfs"), "/dev", Some("tmpfs"), mount_flags, Some("mode=755"))?;
Ok(())
}
fn init_container_log(log: bool) -> Result<()> {
let log_path = Path::new("logs");
create_dir_and_set777(log_path)?;
let log_fd = File::create(log_path.join("log"))?;
let log_fd_raw = log_fd.as_raw_fd();
if log {
unsafe {
dup2(log_fd_raw, 1)?;
dup2(log_fd_raw, 2)?;
}
}
Ok(())
}
fn init_container_env() -> Result<()> {
unsafe {
clearenv().map_err(|e|RockerError::OtherError(format!("清除env失败: {e:?}")))?;
}
Ok(())
}
fn init_container_user(uid: Uid, gid: Gid) -> Result<()>{
unsafe {
setgid(gid.as_raw());
setgroups(&[gid])?;
}
setuid(uid)?;
Ok(())
}
fn create_dir_and_set777<P: AsRef<Path>>(path: P) -> Result<()> {
fs::create_dir_all(&path)?;
fs::set_permissions(&path, PermissionsExt::from_mode(0o777))?;
Ok(())
}
fn parse_cmd(run: &String) -> Vec<CString>{
let args= run
.split(" ")
.filter_map(|s| {
match CString::new(s) {
Ok(cs) => {
Some(cs)
}
Err(e) => {
println!("{e:?}");
None
}
}
})
.collect::<Vec<CString>>();
args
}
fn check_container_is_running(pid: &Pid, main_exe: &Path) -> Result<bool> {
// 检查pid对应的exe是否和外部传过来的相同
let child_exe_s= format!("/proc/{pid}/exe");
let child_exe_path = Path::new(child_exe_s.as_str());
let target_child_exe_path = fs::read_link(child_exe_path)?;
if target_child_exe_path != main_exe {
std::thread::sleep(std::time::Duration::from_millis(10));
return Ok(true);
}
Ok(false)
}
fn run_container(cmd: &String, wait:bool, log:bool, volume_path: &PathBuf) -> Result<String> {
// 禁止同时wait和log
if wait && log {
return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string()));
}
// 初始化容器工作目录
let _container_id = uuid::Uuid::new_v4().to_string();
let container_work_path = Path::new(WORKSPACE).join("containers").join(&_container_id);
let container_upper_path = container_work_path.join("upper");
let container_merged_path = container_work_path.join("merged");
create_dir_and_set777(&container_work_path)?;
create_dir_and_set777(&container_upper_path)?;
create_dir_and_set777(&container_merged_path)?;
let rocker_user_info = User::from_name(USER_NAME)?.ok_or(RockerError::OtherError(format!("没找到 用户: {USER_NAME}")))?;
let rocker_uid = rocker_user_info.uid;
let rocker_gid = rocker_user_info.gid;
let _cb = || {
init_container_overlay(volume_path, &container_upper_path, &container_merged_path).unwrap();
init_container_pivot(&container_merged_path).unwrap();
init_container_mount().unwrap();
init_container_log(log).unwrap();
init_container_env().unwrap();
init_container_user(rocker_uid, rocker_gid).unwrap();
let cmd_vec = parse_cmd(cmd);
execv(&cmd_vec[0], &cmd_vec).unwrap();
0
};
let main_exe = std::env::current_exe()?;
unsafe {
match clone(Box::new(_cb), STACK.as_mut_slice(), CloneFlags::from_bits_truncate(CLONE_FLAG), None) {
Ok(child_pid) => {
println!("clone ok: {child_pid:?}");
// check_container_is_running
while let Ok(running) = check_container_is_running(&child_pid, &main_exe) {
if running {
break;
}
}
// wait
if wait {
match waitpid(child_pid, Some(WaitPidFlag::WUNTRACED)) {
Ok(status) => {
println!("{child_pid:?} exit: {status:?}");
}
Err(e) => {
return Err(RockerError::OtherError(format!("{child_pid} err: {e}")));
}
}
}
}
Err(e) => {
return Err(RockerError::OtherError(format!("clone err: {e}")));
}
}
}
Ok(_container_id)
}
#[derive(Deserialize)]
struct ContainerInfo {
id: String,
image: String,
volume: String,
}
fn save_container_info(container_id: &String) -> Result<()> {
let container_info_path = Path::new(WORKSPACE).join("containers").join(container_id).join("container.json");
let container_info = ContainerInfo {
id: container_id.to_string(),
image: "".to_string(),
volume: "".to_string(),
};
let toml_str = toml::to_string(&container_info)?;
// println!("")
Ok(())
}
fn main() -> Result<()>{
let args = RockerArgs::parse();
if let (Some(cmd), Some(image_name)) = (&args.run, &args.image) {
let volume_path = extend_image(image_name)?;
let container_id = run_container(cmd, args.wait, args.log, &volume_path)?;
}
Ok(())
}
Loading…
Cancel
Save