|
|
@ -1,5 +1,3 @@
|
|
|
|
use std::fs::{remove_dir_all, OpenOptions};
|
|
|
|
|
|
|
|
use std::os::unix::fs::OpenOptionsExt;
|
|
|
|
|
|
|
|
use std::{io, fs, fmt, os, path, process, time};
|
|
|
|
use std::{io, fs, fmt, os, path, process, time};
|
|
|
|
use fmt::Display;
|
|
|
|
use fmt::Display;
|
|
|
|
use os::fd::{AsFd, AsRawFd};
|
|
|
|
use os::fd::{AsFd, AsRawFd};
|
|
|
@ -8,8 +6,8 @@ use path::{Path, PathBuf};
|
|
|
|
use std::sync::OnceLock;
|
|
|
|
use std::sync::OnceLock;
|
|
|
|
|
|
|
|
|
|
|
|
use nix::sched::{clone, CloneCb, CloneFlags, setns};
|
|
|
|
use nix::sched::{clone, CloneCb, CloneFlags, setns};
|
|
|
|
use nix::sys::{signal::{kill, Signal}, wait::{waitpid, WaitPidFlag}};
|
|
|
|
use nix::sys::wait::{waitpid, WaitPidFlag};
|
|
|
|
use nix::unistd::{dup2, getpgid, pivot_root, setgid, setgroups, sethostname, setuid, Gid, Pid, Uid, User};
|
|
|
|
use nix::unistd::{dup2, pivot_root, setgid, setgroups, sethostname, setuid, Gid, Pid, Uid, User};
|
|
|
|
use nix::mount::{mount, MntFlags, MsFlags, umount2};
|
|
|
|
use nix::mount::{mount, MntFlags, MsFlags, umount2};
|
|
|
|
use uuid;
|
|
|
|
use uuid;
|
|
|
|
use toml;
|
|
|
|
use toml;
|
|
|
@ -20,6 +18,8 @@ use error::{Result, RockerError};
|
|
|
|
mod error;
|
|
|
|
mod error;
|
|
|
|
use network::{create_network, remove_network};
|
|
|
|
use network::{create_network, remove_network};
|
|
|
|
mod network;
|
|
|
|
mod network;
|
|
|
|
|
|
|
|
use cgroup::{Cgroup, CgroupLevel};
|
|
|
|
|
|
|
|
mod cgroup;
|
|
|
|
|
|
|
|
|
|
|
|
static WORKSPACE: &str = "/home/rocker";
|
|
|
|
static WORKSPACE: &str = "/home/rocker";
|
|
|
|
static USER_NAME: &str = "rocker";
|
|
|
|
static USER_NAME: &str = "rocker";
|
|
|
@ -73,6 +73,9 @@ struct RockerArgs {
|
|
|
|
// --psa
|
|
|
|
// --psa
|
|
|
|
#[arg(long)]
|
|
|
|
#[arg(long)]
|
|
|
|
psa: bool,
|
|
|
|
psa: bool,
|
|
|
|
|
|
|
|
// --root
|
|
|
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
|
|
|
root: bool,
|
|
|
|
|
|
|
|
|
|
|
|
// rm "container_id_1, container_id_2, container_id_3"
|
|
|
|
// rm "container_id_1, container_id_2, container_id_3"
|
|
|
|
#[arg(long)]
|
|
|
|
#[arg(long)]
|
|
|
@ -86,6 +89,8 @@ struct RockerArgs {
|
|
|
|
#[arg(long)]
|
|
|
|
#[arg(long)]
|
|
|
|
restart: Option<String>,
|
|
|
|
restart: Option<String>,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
|
|
|
cgroup: Option<String>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
macro_rules! rocker_println {
|
|
|
|
macro_rules! rocker_println {
|
|
|
@ -125,11 +130,11 @@ fn extend_image(image_name: &String) -> Result<PathBuf> {
|
|
|
|
if out.status.success() {
|
|
|
|
if out.status.success() {
|
|
|
|
println!("解压缩完毕: {image_name:?}");
|
|
|
|
println!("解压缩完毕: {image_name:?}");
|
|
|
|
// 把解压缩后的文件全部给 rocker:rocker
|
|
|
|
// 把解压缩后的文件全部给 rocker:rocker
|
|
|
|
let _ = process::Command::new("chown")
|
|
|
|
// let _ = process::Command::new("chown")
|
|
|
|
.arg("-R")
|
|
|
|
// .arg("-R")
|
|
|
|
.arg("rocker:rocker")
|
|
|
|
// .arg("rocker:rocker")
|
|
|
|
.arg(volume_path_str)
|
|
|
|
// .arg(volume_path_str)
|
|
|
|
.output()?;
|
|
|
|
// .output()?;
|
|
|
|
Ok(volume_path)
|
|
|
|
Ok(volume_path)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// 删除 volume_path
|
|
|
|
// 删除 volume_path
|
|
|
@ -164,7 +169,13 @@ fn init_container_overlay<P: AsRef<Path>>(volume_path: P, upper_path: P, merged_
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn init_container_dev<P: AsRef<Path>>(container_merged_path: P) -> Result<()> {
|
|
|
|
fn init_container_dev<P: AsRef<Path>>(container_merged_path: P) -> Result<()> {
|
|
|
|
let dev_vec = [("urandom", 0), ("random", 0), ("null", 0), ("zero", 0), ("shm", 1)];
|
|
|
|
let dev_vec = [
|
|
|
|
|
|
|
|
("urandom", 0),
|
|
|
|
|
|
|
|
("random", 0),
|
|
|
|
|
|
|
|
("null", 0),
|
|
|
|
|
|
|
|
("zero", 0),
|
|
|
|
|
|
|
|
// ("shm", 1),
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
for (dev, tp) in dev_vec {
|
|
|
|
for (dev, tp) in dev_vec {
|
|
|
|
let host_dev_path = format!("/dev/{dev}");
|
|
|
|
let host_dev_path = format!("/dev/{dev}");
|
|
|
@ -310,7 +321,7 @@ fn init_container_user(uid: Uid, gid: Gid) -> Result<()>{
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn create_dir<P: AsRef<Path>>(path: P, is_any:bool) -> Result<()> {
|
|
|
|
pub fn create_dir<P: AsRef<Path>>(path: P, is_any:bool) -> Result<()> {
|
|
|
|
fs::create_dir_all(&path)?;
|
|
|
|
fs::create_dir_all(&path)?;
|
|
|
|
if is_any {
|
|
|
|
if is_any {
|
|
|
|
fs::set_permissions(&path, PermissionsExt::from_mode(0o777))?;
|
|
|
|
fs::set_permissions(&path, PermissionsExt::from_mode(0o777))?;
|
|
|
@ -348,7 +359,7 @@ fn create_pause(container_root_pause_path: &Path) -> Result<()> {
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, container_merged_pause_path: &PathBuf) -> Result<i32>{
|
|
|
|
fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, container_merged_pause_path: &PathBuf) -> Result<()>{
|
|
|
|
match unsafe {clone(cb, STACK.as_mut_slice(), clong_flags, None)} {
|
|
|
|
match unsafe {clone(cb, STACK.as_mut_slice(), clong_flags, None)} {
|
|
|
|
Ok(child_pid) => {
|
|
|
|
Ok(child_pid) => {
|
|
|
|
{ // 执行成功就保存吧~
|
|
|
|
{ // 执行成功就保存吧~
|
|
|
@ -359,18 +370,18 @@ fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, c
|
|
|
|
|
|
|
|
|
|
|
|
// exec之前的步骤
|
|
|
|
// exec之前的步骤
|
|
|
|
create_network(&container_info.id, child_pid.as_raw());
|
|
|
|
create_network(&container_info.id, child_pid.as_raw());
|
|
|
|
|
|
|
|
Cgroup::create(&container_info.id, child_pid.as_raw(), CgroupLevel::from(container_info.cgroup_level.as_str()))?;
|
|
|
|
|
|
|
|
|
|
|
|
// 删除 pause标志文件, 解开阻塞, 使其执行exec
|
|
|
|
// 删除 pause标志文件, 解开阻塞, 使其执行exec
|
|
|
|
for _ in 0..500 {
|
|
|
|
(0..100).any(|i| {
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(i));
|
|
|
|
if std::fs::remove_file(container_merged_pause_path).is_ok() {
|
|
|
|
std::fs::remove_file(container_merged_pause_path).is_ok()
|
|
|
|
break;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否执行exec了
|
|
|
|
// 检查是否执行exec了
|
|
|
|
let main_exe = std::env::current_exe()?;
|
|
|
|
let main_exe = std::env::current_exe()?;
|
|
|
|
for _ in 0..500 {
|
|
|
|
for i in 0..100 {
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(i));
|
|
|
|
if let Ok(true) = check_container_is_running(&child_pid, &main_exe) {
|
|
|
|
if let Ok(true) = check_container_is_running(&child_pid, &main_exe) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -388,7 +399,7 @@ fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(child_pid.as_raw())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
Err(e) => {
|
|
|
|
Err(RockerError::OtherError(format!("clone err: {e}")))
|
|
|
|
Err(RockerError::OtherError(format!("clone err: {e}")))
|
|
|
@ -396,7 +407,7 @@ fn start(container_info: &ContainerInfo, cb: CloneCb, clong_flags: CloneFlags, c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -> Result<i32> {
|
|
|
|
fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -> Result<()> {
|
|
|
|
// 禁止同时wait和log
|
|
|
|
// 禁止同时wait和log
|
|
|
|
if container_info.wait && container_info.log {
|
|
|
|
if container_info.wait && container_info.log {
|
|
|
|
return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string()));
|
|
|
|
return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string()));
|
|
|
@ -425,7 +436,9 @@ fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -
|
|
|
|
let _cb = || {
|
|
|
|
let _cb = || {
|
|
|
|
init_exec_ns(container_info.pid).unwrap();
|
|
|
|
init_exec_ns(container_info.pid).unwrap();
|
|
|
|
let env_vec = get_env_vec(&Default::default()).unwrap();
|
|
|
|
let env_vec = get_env_vec(&Default::default()).unwrap();
|
|
|
|
init_container_user(rocker_uid, rocker_gid).unwrap();
|
|
|
|
if container_info.root == false {
|
|
|
|
|
|
|
|
init_container_user(rocker_uid, rocker_gid).unwrap();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
init_container_env(env_vec).unwrap();
|
|
|
|
init_container_env(env_vec).unwrap();
|
|
|
|
create_pause(container_root_pause_path).unwrap();
|
|
|
|
create_pause(container_root_pause_path).unwrap();
|
|
|
@ -477,8 +490,10 @@ fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置用户
|
|
|
|
// 设置用户
|
|
|
|
init_container_user(rocker_uid, rocker_gid).unwrap();
|
|
|
|
if container_info.root == false {
|
|
|
|
|
|
|
|
init_container_user(rocker_uid, rocker_gid).unwrap();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 暂停等待外部主进程设置网络设备
|
|
|
|
// 暂停等待外部主进程设置网络设备
|
|
|
|
create_pause(&container_root_pause_path).unwrap();
|
|
|
|
create_pause(&container_root_pause_path).unwrap();
|
|
|
|
while container_root_pause_path.exists() {
|
|
|
|
while container_root_pause_path.exists() {
|
|
|
@ -514,7 +529,6 @@ impl Display for ContainerStatus {
|
|
|
|
Self::STOP => write!(f, "🔴"),
|
|
|
|
Self::STOP => write!(f, "🔴"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -530,6 +544,9 @@ struct ContainerInfo {
|
|
|
|
env: String, // a=1,b=2,c=3 或者 env文件路径
|
|
|
|
env: String, // a=1,b=2,c=3 或者 env文件路径
|
|
|
|
log: bool,
|
|
|
|
log: bool,
|
|
|
|
wait: bool,
|
|
|
|
wait: bool,
|
|
|
|
|
|
|
|
root: bool,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cgroup_level: String, // one/two/three
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl ContainerInfo {
|
|
|
|
impl ContainerInfo {
|
|
|
@ -551,39 +568,25 @@ impl Display for ContainerInfo {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn save_container_info(args: &RockerArgs, container_id: &String, pid: i32) -> Result<()> {
|
|
|
|
|
|
|
|
let container_info_path = Path::new(WORKSPACE).join("containers").join(container_id).join(INFO_FILE);
|
|
|
|
|
|
|
|
let container_info = ContainerInfo {
|
|
|
|
|
|
|
|
id: container_id.clone(),
|
|
|
|
|
|
|
|
pid: pid,
|
|
|
|
|
|
|
|
run: args.run.as_ref().unwrap().clone(),
|
|
|
|
|
|
|
|
image: args.image.as_ref().unwrap().clone(),
|
|
|
|
|
|
|
|
volume: args.volume.clone().unwrap_or("".to_string()),
|
|
|
|
|
|
|
|
env: args.env.clone().unwrap_or("".to_string()),
|
|
|
|
|
|
|
|
status: ContainerStatus::READY,
|
|
|
|
|
|
|
|
log: args.log,
|
|
|
|
|
|
|
|
wait: args.wait,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
let toml_str = toml::to_string(&container_info)?;
|
|
|
|
|
|
|
|
fs::write(container_info_path, toml_str)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn get_container_info(container_id: &str) -> Result<ContainerInfo> {
|
|
|
|
fn get_container_info(container_id: &str) -> Result<ContainerInfo> {
|
|
|
|
let container_work_path = Path::new(WORKSPACE).join("containers").join(container_id);
|
|
|
|
let container_work_path = Path::new(WORKSPACE).join("containers").join(container_id);
|
|
|
|
let container_info_path = container_work_path.join(INFO_FILE);
|
|
|
|
let container_info_path = container_work_path.join(INFO_FILE);
|
|
|
|
let info_str = fs::read_to_string(container_info_path)?;
|
|
|
|
let info_str = fs::read_to_string(container_info_path)?;
|
|
|
|
let mut container_info: ContainerInfo = toml::from_str(&info_str)?;
|
|
|
|
let mut container_info: ContainerInfo = toml::from_str(&info_str)?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// todo 判断当前进程组 是否还有进程
|
|
|
|
|
|
|
|
let cgroup = Cgroup::from(&container_info);
|
|
|
|
|
|
|
|
|
|
|
|
// 判断是否正在运行, 进入proc/pid/判断当前进程网络中是否有下面的设备
|
|
|
|
// 判断是否正在运行, 进入proc/pid/判断当前进程网络中是否有下面的设备
|
|
|
|
let dev_path = Path::new("/proc").join(container_info.pid.to_string()).join("net").join("dev");
|
|
|
|
// let dev_path = Path::new("/proc").join(container_info.pid.to_string()).join("net").join("dev");
|
|
|
|
let is_running = if let Ok(dev_text) = fs::read_to_string(dev_path){
|
|
|
|
// let is_running = if let Ok(dev_text) = fs::read_to_string(dev_path){
|
|
|
|
let slave_veth_name = format!("ro_{container_id}_3");
|
|
|
|
// let slave_veth_name = format!("ro_{container_id}_3");
|
|
|
|
dev_text.lines().any(|l|l.starts_with(&slave_veth_name))
|
|
|
|
// dev_text.lines().any(|l|l.starts_with(&slave_veth_name))
|
|
|
|
} else {
|
|
|
|
// } else {
|
|
|
|
false
|
|
|
|
// false
|
|
|
|
};
|
|
|
|
// };
|
|
|
|
if is_running {
|
|
|
|
|
|
|
|
|
|
|
|
if cgroup.procs.len() > 0 {
|
|
|
|
container_info.status = ContainerStatus::RUNNING;
|
|
|
|
container_info.status = ContainerStatus::RUNNING;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
container_info.status = ContainerStatus::STOP;
|
|
|
|
container_info.status = ContainerStatus::STOP;
|
|
|
@ -624,17 +627,15 @@ fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> {
|
|
|
|
return Ok(())
|
|
|
|
return Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for container_id in containers_id.split(" ") {
|
|
|
|
for container_id in containers_id.split(" ") {
|
|
|
|
|
|
|
|
// 容器网络删除
|
|
|
|
|
|
|
|
remove_network(container_id);
|
|
|
|
|
|
|
|
|
|
|
|
let container_work_path = containers_path.join(container_id);
|
|
|
|
let container_work_path = containers_path.join(container_id);
|
|
|
|
let container_merged_path = container_work_path.join("merged");
|
|
|
|
let container_merged_path = container_work_path.join("merged");
|
|
|
|
if let Ok(container_info) = get_container_info(container_id) {
|
|
|
|
if let Ok(container_info) = get_container_info(container_id) {
|
|
|
|
// 正在运行中的需要 kill
|
|
|
|
// 删除进程组
|
|
|
|
if container_info.status == ContainerStatus::RUNNING {
|
|
|
|
Cgroup::remove(container_id);
|
|
|
|
let _ = kill(Pid::from_raw(-container_info.pid), Signal::SIGKILL);
|
|
|
|
|
|
|
|
let pid_path = Path::new("/proc").join(container_info.pid.to_string());
|
|
|
|
|
|
|
|
while pid_path.exists() {
|
|
|
|
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 卸载自定义挂载点
|
|
|
|
// 卸载自定义挂载点
|
|
|
|
if container_info.volume != "" {
|
|
|
|
if container_info.volume != "" {
|
|
|
|
container_info.volume
|
|
|
|
container_info.volume
|
|
|
@ -650,14 +651,16 @@ fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> {
|
|
|
|
.for_each(|s| {
|
|
|
|
.for_each(|s| {
|
|
|
|
match umount2(s.as_str(), MntFlags::MNT_DETACH) {
|
|
|
|
match umount2(s.as_str(), MntFlags::MNT_DETACH) {
|
|
|
|
Ok(_) => println!("卸载自定卷{s}"),
|
|
|
|
Ok(_) => println!("卸载自定卷{s}"),
|
|
|
|
Err(e) => println!("卸载卷{s}失败: {e:?}"),
|
|
|
|
Err(e) => println!("卸载自定卷{s}失败: {e:?}"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 卸载dev文件夹中的设备
|
|
|
|
// 卸载dev文件夹中的设备
|
|
|
|
let container_dev_path = container_merged_path.join("dev");
|
|
|
|
let container_dev_path = container_merged_path.join("dev");
|
|
|
|
container_dev_path.read_dir()?.filter_map(|d|d.ok())
|
|
|
|
let _ = container_dev_path.read_dir().map(|dev| {
|
|
|
|
.for_each(|p|{let _ = umount2(p.path().to_str().unwrap(), MntFlags::MNT_DETACH);});
|
|
|
|
dev.filter_map(|d|d.ok())
|
|
|
|
|
|
|
|
.for_each(|p|{let _ = umount2(p.path().to_str().unwrap(), MntFlags::MNT_DETACH);});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 卸载overlayfs
|
|
|
|
// 卸载overlayfs
|
|
|
|
match umount2(container_merged_path.to_str().unwrap(), MntFlags::MNT_DETACH) {
|
|
|
|
match umount2(container_merged_path.to_str().unwrap(), MntFlags::MNT_DETACH) {
|
|
|
@ -676,14 +679,14 @@ fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> {
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
println!("容器不存在: {container_id}, 强制删除");
|
|
|
|
println!("容器不存在: {container_id}, 强制删除");
|
|
|
|
// 需要强制删除一下目录
|
|
|
|
// 需要强制删除一下目录
|
|
|
|
match fs::remove_dir_all(&container_work_path) {
|
|
|
|
if container_work_path.exists() {
|
|
|
|
Ok(_) => println!("强制删除 {container_work_path:?} 成功"),
|
|
|
|
match fs::remove_dir_all(&container_work_path) {
|
|
|
|
Err(e) => println!("强制删除失败: {e:?}"),
|
|
|
|
Ok(_) => println!("强制删除 {container_work_path:?} 成功"),
|
|
|
|
|
|
|
|
Err(e) => println!("强制删除失败: {e:?}"),
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 容器网络删除
|
|
|
|
|
|
|
|
remove_network(container_id);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -708,7 +711,9 @@ fn main() -> Result<()>{
|
|
|
|
env: args.env.clone().unwrap_or_default(),
|
|
|
|
env: args.env.clone().unwrap_or_default(),
|
|
|
|
status: ContainerStatus::READY,
|
|
|
|
status: ContainerStatus::READY,
|
|
|
|
log: args.log,
|
|
|
|
log: args.log,
|
|
|
|
wait: args.wait
|
|
|
|
wait: args.wait,
|
|
|
|
|
|
|
|
cgroup_level: args.cgroup.clone().unwrap_or(CgroupLevel::default().to_string()),
|
|
|
|
|
|
|
|
root: args.root
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(None, None, Some(_container_id)) => {
|
|
|
|
(None, None, Some(_container_id)) => {
|
|
|
|