|
|
@ -37,6 +37,8 @@ struct RockerArgs {
|
|
|
|
image: Option<String>,
|
|
|
|
image: Option<String>,
|
|
|
|
#[arg(long)]
|
|
|
|
#[arg(long)]
|
|
|
|
volume: Option<String>,
|
|
|
|
volume: Option<String>,
|
|
|
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
|
|
|
env: Option<String>,
|
|
|
|
|
|
|
|
|
|
|
|
#[arg(long)]
|
|
|
|
#[arg(long)]
|
|
|
|
log: bool,
|
|
|
|
log: bool,
|
|
|
@ -56,7 +58,12 @@ struct RockerArgs {
|
|
|
|
|
|
|
|
|
|
|
|
// rm container_id
|
|
|
|
// rm container_id
|
|
|
|
#[arg(long)]
|
|
|
|
#[arg(long)]
|
|
|
|
rm: Option<String>
|
|
|
|
rm: Option<String>,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// stop container_id
|
|
|
|
|
|
|
|
#[arg(long)]
|
|
|
|
|
|
|
|
stop: Option<String>
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -276,21 +283,18 @@ fn check_container_is_running(pid: &Pid, main_exe: &Path) -> Result<bool> {
|
|
|
|
let child_exe_path = Path::new(child_exe_s.as_str());
|
|
|
|
let child_exe_path = Path::new(child_exe_s.as_str());
|
|
|
|
let target_child_exe_path = fs::read_link(child_exe_path)?;
|
|
|
|
let target_child_exe_path = fs::read_link(child_exe_path)?;
|
|
|
|
if target_child_exe_path != main_exe {
|
|
|
|
if target_child_exe_path != main_exe {
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
|
|
|
|
|
|
return Ok(true);
|
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn run_container(cmd: &String, args: &RockerArgs, volume_path: &PathBuf) -> Result<(String, i32)> {
|
|
|
|
fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume_path: &PathBuf) -> Result<i32> {
|
|
|
|
// 禁止同时wait和log
|
|
|
|
// 禁止同时wait和log
|
|
|
|
if args.wait && args.log {
|
|
|
|
if args.wait && args.log {
|
|
|
|
return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string()));
|
|
|
|
return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化容器工作目录
|
|
|
|
// 初始化容器工作目录
|
|
|
|
let _container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string();
|
|
|
|
|
|
|
|
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_upper_path = container_work_path.join("upper");
|
|
|
|
let container_upper_path = container_work_path.join("upper");
|
|
|
|
let container_merged_path = container_work_path.join("merged");
|
|
|
|
let container_merged_path = container_work_path.join("merged");
|
|
|
@ -315,7 +319,12 @@ fn run_container(cmd: &String, args: &RockerArgs, volume_path: &PathBuf) -> Resu
|
|
|
|
init_container_user(rocker_uid, rocker_gid).unwrap();
|
|
|
|
init_container_user(rocker_uid, rocker_gid).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
let cmd_vec = parse_cmd(cmd);
|
|
|
|
let cmd_vec = parse_cmd(cmd);
|
|
|
|
execv(&cmd_vec[0], &cmd_vec).unwrap();
|
|
|
|
match execv(&cmd_vec[0], &cmd_vec) {
|
|
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
|
|
println!("execv {cmd_vec:?}失败: {e:?}");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => {},
|
|
|
|
|
|
|
|
};
|
|
|
|
0
|
|
|
|
0
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -326,10 +335,17 @@ fn run_container(cmd: &String, args: &RockerArgs, volume_path: &PathBuf) -> Resu
|
|
|
|
println!("clone ok: {child_pid:?}");
|
|
|
|
println!("clone ok: {child_pid:?}");
|
|
|
|
|
|
|
|
|
|
|
|
// check_container_is_running
|
|
|
|
// check_container_is_running
|
|
|
|
|
|
|
|
let mut cnt = 0;
|
|
|
|
while let Ok(running) = check_container_is_running(&child_pid, &main_exe) {
|
|
|
|
while let Ok(running) = check_container_is_running(&child_pid, &main_exe) {
|
|
|
|
|
|
|
|
cnt += 1;
|
|
|
|
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
|
|
if running {
|
|
|
|
if running {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if cnt > 1000 {
|
|
|
|
|
|
|
|
println!("{child_pid} 启动 超时");
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// wait
|
|
|
|
// wait
|
|
|
@ -339,11 +355,11 @@ fn run_container(cmd: &String, args: &RockerArgs, volume_path: &PathBuf) -> Resu
|
|
|
|
println!("{child_pid:?} exit: {status:?}");
|
|
|
|
println!("{child_pid:?} exit: {status:?}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
Err(e) => {
|
|
|
|
return Err(RockerError::OtherError(format!("{child_pid} err: {e}")));
|
|
|
|
println!("{child_pid} wait err: {e}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok((_container_id, child_pid.as_raw()))
|
|
|
|
Ok(child_pid.as_raw())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
Err(e) => {
|
|
|
|
return Err(RockerError::OtherError(format!("clone err: {e}")));
|
|
|
|
return Err(RockerError::OtherError(format!("clone err: {e}")));
|
|
|
@ -398,7 +414,7 @@ fn save_container_info(args: &RockerArgs, container_id: &String, pid: i32) -> Re
|
|
|
|
run: args.run.as_ref().unwrap().clone(),
|
|
|
|
run: args.run.as_ref().unwrap().clone(),
|
|
|
|
image: args.image.as_ref().unwrap().clone(),
|
|
|
|
image: args.image.as_ref().unwrap().clone(),
|
|
|
|
volume: args.volume.clone().unwrap_or("".to_string()),
|
|
|
|
volume: args.volume.clone().unwrap_or("".to_string()),
|
|
|
|
env: "".to_string(),
|
|
|
|
env: args.env.clone().unwrap_or("".to_string()),
|
|
|
|
status: ContainerStatus::READY,
|
|
|
|
status: ContainerStatus::READY,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
let toml_str = toml::to_string(&container_info)?;
|
|
|
|
let toml_str = toml::to_string(&container_info)?;
|
|
|
@ -454,8 +470,8 @@ fn show_containers(is_show_all: bool) -> Result<()> {
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn delete_container(containers_id: &str) -> Result<()> {
|
|
|
|
fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> {
|
|
|
|
for container_id in containers_id.split(",") {
|
|
|
|
for container_id in containers_id.split(" ") {
|
|
|
|
if let Ok(container_info) = get_container_info(container_id) {
|
|
|
|
if let Ok(container_info) = get_container_info(container_id) {
|
|
|
|
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_merged_path = container_work_path.join("merged");
|
|
|
|
let container_merged_path = container_work_path.join("merged");
|
|
|
@ -463,24 +479,35 @@ fn delete_container(containers_id: &str) -> Result<()> {
|
|
|
|
if container_info.status == ContainerStatus::RUNNING {
|
|
|
|
if container_info.status == ContainerStatus::RUNNING {
|
|
|
|
kill(Pid::from_raw(container_info.pid), Signal::SIGTERM)?;
|
|
|
|
kill(Pid::from_raw(container_info.pid), Signal::SIGTERM)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 卸载自定义挂载点
|
|
|
|
// 卸载自定义挂载点
|
|
|
|
let volumes_path = container_info.volume
|
|
|
|
if container_info.volume != "" {
|
|
|
|
|
|
|
|
container_info.volume
|
|
|
|
.split(",")
|
|
|
|
.split(",")
|
|
|
|
.filter_map(|v| v.split(":").last())
|
|
|
|
.filter_map(|v| v.split(":").last())
|
|
|
|
.map(|v| container_merged_path.join(v).to_string_lossy().to_string())
|
|
|
|
.map(|v| container_merged_path.join(v).to_string_lossy().to_string())
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
.for_each(|s| {
|
|
|
|
for volume_path in volumes_path {
|
|
|
|
match umount(s.as_str()) {
|
|
|
|
umount(volume_path.as_str())?;
|
|
|
|
Ok(s) => println!("卸载自定卷: {s:?}"),
|
|
|
|
println!("卸载卷: {volume_path:?}");
|
|
|
|
Err(e) => panic!("卸载卷失败: {e:?}"),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 卸载overlayfs
|
|
|
|
// 卸载overlayfs
|
|
|
|
umount(container_merged_path.to_str().unwrap())?;
|
|
|
|
match umount(container_merged_path.to_str().unwrap()) {
|
|
|
|
|
|
|
|
Ok(s) => println!("卸载overlayfs卷: {s:?}"),
|
|
|
|
|
|
|
|
Err(e) => println!("卸载overlayfs失败: {e:?}"),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
println!("停止容器: {container_id:?}");
|
|
|
|
// 删除容器目录
|
|
|
|
// 删除容器目录
|
|
|
|
fs::remove_dir_all(container_work_path)?;
|
|
|
|
if is_remove {
|
|
|
|
println!("删除容器: {container_id:?}");
|
|
|
|
match fs::remove_dir_all(container_work_path) {
|
|
|
|
|
|
|
|
Ok(s) => println!("删除容器 {container_id} 成功"),
|
|
|
|
|
|
|
|
Err(e) => println!("删除容器失败: {e:?}"),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
println!("容器不存在: {container_id}")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -493,15 +520,34 @@ fn main() -> Result<()>{
|
|
|
|
if let (Some(cmd), Some(image_name)) = (&args.run, &args.image) {
|
|
|
|
if let (Some(cmd), Some(image_name)) = (&args.run, &args.image) {
|
|
|
|
// run
|
|
|
|
// run
|
|
|
|
let volume_path = extend_image(image_name)?;
|
|
|
|
let volume_path = extend_image(image_name)?;
|
|
|
|
let (container_id, pid) = run_container(cmd, &args, &volume_path)?;
|
|
|
|
let container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string();
|
|
|
|
|
|
|
|
let mut pid = -1;
|
|
|
|
|
|
|
|
match run_container(&container_id,&cmd, &args, &volume_path) {
|
|
|
|
|
|
|
|
Ok(child_pid) => {
|
|
|
|
|
|
|
|
pid = child_pid;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
|
|
println!("run_container失败: {e}");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
save_container_info(&args, &container_id, pid)?; // todo 无论出不错, 都要保存一个信息, 后面需要删除用清理
|
|
|
|
save_container_info(&args, &container_id, pid)?; // todo 无论出不错, 都要保存一个信息, 后面需要删除用清理
|
|
|
|
} else if args.ps || args.psa {
|
|
|
|
} else if args.ps || args.psa {
|
|
|
|
// --ps
|
|
|
|
// --ps
|
|
|
|
show_containers(args.psa)?
|
|
|
|
show_containers(args.psa)?
|
|
|
|
} else if let Some(containers_id) = &args.rm {
|
|
|
|
} else if let Some(containers_id) = &args.rm {
|
|
|
|
// --rm
|
|
|
|
// --rm
|
|
|
|
delete_container(containers_id)?;
|
|
|
|
stop_container(containers_id, true)?;
|
|
|
|
}
|
|
|
|
} else if let Some(containers_id) = &args.stop {
|
|
|
|
|
|
|
|
// --stop
|
|
|
|
|
|
|
|
stop_container(containers_id, false)?;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// } else if let Some(containers_id) = &args.start {
|
|
|
|
|
|
|
|
// // --start
|
|
|
|
|
|
|
|
// start_container(containers_id)?;
|
|
|
|
|
|
|
|
// } else if let Some(containers_id) = &args.exec {
|
|
|
|
|
|
|
|
// // --exec
|
|
|
|
|
|
|
|
// exec_container(containers_id, &cmd, &args)?;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// exec
|
|
|
|
// exec
|
|
|
|
|
|
|
|
|
|
|
|