diff --git a/src/main.rs b/src/main.rs index 45f4f9b..aaf7957 100644 --- a/src/main.rs +++ b/src/main.rs @@ -188,30 +188,20 @@ fn init_container_custom_volume>(container_merged_path: P, custom } -fn init_container_env(env: Option<&String>) -> Result<()>{ +fn init_container_env(env: &String) -> Result<()>{ for (k, _) in std::env::vars(){ std::env::remove_var(k); } - - let env_vec = if let Some(env) = env { - let mut env_vec = if env.starts_with("./") || env.starts_with("/") { - // 读取出路径指定的文件作为env - let env_path = Path::new(env); - let mut env_file = fs::File::open(env_path)?; - let text = { - let mut s = String::new(); - env_file.read_to_string(&mut s)?; - s - }; - text.lines().map(String::from).collect::>() - } else { - env.split(",").map(String::from).collect::>() - }; - env_vec.push(r#"PS1=\u\h\W\$ "#.to_string()); - env_vec + let mut env_vec = if env.starts_with("./") || env.starts_with("/") { + // 读取出路径指定的文件作为env + let env_text = fs::read_to_string(env)?; + env_text.lines().map(String::from).collect::>() } else { - vec![r#"PS1=\u\h\W\$ "#.to_string()] + env.split(",").map(String::from).collect::>() }; + + env_vec.push(r#"PS1=\u\h\W\$ "#.to_string()); + for item_env in env_vec.iter() { let item_env_v = item_env.split("=").collect::>(); if item_env_v.len() == 2 { @@ -327,12 +317,17 @@ fn create_pause(container_root_pause_path: &Path) -> Result<()> { Ok(()) } -fn start(is_wait: bool, cb: CloneCb, clong_flags: CloneFlags, container_id: &String, container_merged_pause_path: &PathBuf) -> Result{ +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)} { Ok(child_pid) => { - println!("clone ok: {child_pid:?}"); + { + let mut _container_info = container_info.clone(); + _container_info.pid = child_pid.as_raw(); + let _ = _container_info.flush(); + } + // exec之前的步骤 - create_network(container_id, child_pid.as_raw()); + create_network(&container_info.id, child_pid.as_raw()); // 删除 pause标志文件, 解开阻塞, 使其执行exec while std::fs::remove_file(container_merged_pause_path).is_err(){ std::thread::sleep(std::time::Duration::from_millis(10)); @@ -355,7 +350,7 @@ fn start(is_wait: bool, cb: CloneCb, clong_flags: CloneFlags, container_id: &Str println!("启动用时: {}ms", START_T.get().unwrap().elapsed().as_millis()); // wait - if is_wait { + if container_info.wait { match waitpid(child_pid, Some(WaitPidFlag::WUNTRACED)) { Ok(status) => { println!("{child_pid:?} exit: {status:?}"); @@ -368,66 +363,68 @@ fn start(is_wait: bool, cb: CloneCb, clong_flags: CloneFlags, container_id: &Str Ok(child_pid.as_raw()) } Err(e) => { - Err(RockerError::OtherError(format!("clone err: {e}"))) } } } -fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume_path: &PathBuf, is_exec: bool) -> Result { +fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -> Result { // 禁止同时wait和log - if args.wait && args.log { + if container_info.wait && container_info.log { return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string())); } let clone_flags; - let container_work_path = Path::new(WORKSPACE).join("containers").join(&_container_id); + + let container_work_path = Path::new(WORKSPACE).join("containers").join(&container_info.id); let container_upper_path = container_work_path.join("upper"); let container_merged_path = container_work_path.join("merged"); let container_merged_pause_path = container_work_path.join("merged").join("pause"); let container_root_pause_path = Path::new("/pause"); + // 初始化容器工作目录 + if create_dir(&container_work_path, true).is_ok() && create_dir(&container_upper_path, true).is_ok() && create_dir(&container_merged_path, true).is_ok() { + println!("容器工作目录创建成功"); + } else { + return Err(RockerError::OtherError("容器工作目录创建失败".to_string())); + } + 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 = if is_exec { + let _cb = if let Some(exec_cmd) = is_exec_cmd { let _cb = || { - let container_info = get_container_info(_container_id).unwrap(); init_exec_ns(container_info.pid).unwrap(); - init_container_env(None).unwrap(); + init_container_env(&Default::default()).unwrap(); init_container_user(rocker_uid, rocker_gid).unwrap(); + create_pause(container_root_pause_path).unwrap(); while container_merged_pause_path.exists() { std::thread::sleep(std::time::Duration::from_millis(10)); } - let cmd_vec = cmd.split(" ").collect::>(); + let cmd_vec = exec_cmd.split(" ").collect::>(); let err = process::Command::new(cmd_vec[0]) .args(&cmd_vec[1..]) .exec(); println!("execv {cmd_vec:?}失败: {err:?}"); 0isize }; - clone_flags = CloneFlags::empty(); Box::new(_cb) as CloneCb } else { - // 初始化容器工作目录 - create_dir(&container_work_path, true)?; - create_dir(&container_upper_path, true)?; - create_dir(&container_merged_path, true)?; - let _cb = || { - init_container_overlay(volume_path, &container_upper_path, &container_merged_path).unwrap(); - if let Some(custom_volume) = &args.volume { - init_container_custom_volume(&container_merged_path, custom_volume).unwrap(); + let volume_path = extend_image(&container_info.image).unwrap(); + init_container_overlay(&volume_path, &container_upper_path, &container_merged_path).unwrap(); + if container_info.volume.len() > 3 { // .:. 最少也要有3个字符吧 + init_container_custom_volume(&container_merged_path, &container_info.volume).unwrap(); } sethostname(USER_NAME).unwrap(); - init_container_env(args.env.as_ref()).unwrap(); + init_container_env(&container_info.env).unwrap(); init_container_pivot(&container_merged_path).unwrap(); init_container_mount().unwrap(); - init_container_log(args.log).unwrap(); + init_container_log(container_info.log).unwrap(); init_container_user(rocker_uid, rocker_gid).unwrap(); create_pause(&container_root_pause_path).unwrap(); @@ -435,7 +432,7 @@ fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume std::thread::sleep(std::time::Duration::from_millis(10)); } - let cmd_vec = cmd.split(" ").collect::>(); + let cmd_vec = container_info.run.split(" ").collect::>(); let err = process::Command::new(cmd_vec[0]) .args(&cmd_vec[1..]) .exec(); @@ -446,10 +443,10 @@ fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume Box::new(_cb) as CloneCb }; - start(args.wait, _cb, clone_flags, _container_id, &container_merged_pause_path) + start(container_info, _cb, clone_flags, &container_merged_pause_path) } -#[derive(Deserialize, Serialize, Debug, PartialEq)] +#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)] enum ContainerStatus { READY, RUNNING, @@ -468,7 +465,7 @@ impl Display for ContainerStatus { } -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, Clone)] struct ContainerInfo { id: String, pid: i32, @@ -640,59 +637,38 @@ fn main() -> Result<()>{ let mut args = RockerArgs::parse(); if args.image.is_some() || args.restart.is_some() { - let volume_path; - let container_id; - let cmd; - match (&args.run, &args.image, &args.restart) { - (Some(_cmd), Some(image_name), None) => { - volume_path = extend_image(image_name)?; - container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string(); - cmd = _cmd.clone(); + let container_info = match (&args.run, &args.image, &args.restart) { + (Some(cmd), Some(image), None) => { + ContainerInfo { + id: uuid::Uuid::new_v4().to_string()[0..8].to_string(), + pid: -1, + run: cmd.clone(), + image: image.clone(), + volume: args.volume.clone().unwrap_or_default(), + env: args.env.clone().unwrap_or_default(), + status: ContainerStatus::READY, + log: args.log, + wait: args.wait + } } (None, None, Some(_container_id)) => { - let container_info = get_container_info(_container_id)?; - volume_path = extend_image(&container_info.image)?; - container_id = _container_id.clone(); - cmd = container_info.run; - args.run = Some(cmd.clone()); - args.image = Some(container_info.image); - args.log = container_info.log; - if container_info.volume.len() > 0 { - args.volume = Some(container_info.volume); - } - if container_info.env.len() > 0 { - args.env = Some(container_info.env); - } - stop_container(&container_id, false)?; + stop_container(_container_id, false)?; + get_container_info(_container_id)? } _ => { unreachable!() } - } + }; - CONTAINER_INFO.get_or_init(||{ - ContainerInfo { - id: container_id.clone(), - pid: -1, - run: args.run.as_ref().unwrap().clone(), - image: args.image.as_ref().unwrap().clone(), - volume: args.volume.clone().unwrap_or_default(), - env: args.env.clone().unwrap_or_default(), - status: ContainerStatus::READY, - log: args.log, - wait: args.wait - } - }); - let container_info = CONTAINER_INFO.get().unwrap(); - match run_container(&container_id, &cmd, &args, &volume_path, false) { + match run_container(&container_info, None) { Ok(child_pid) => { - // save_container_info(&args, &container_id, child_pid)?; + println!("容器 {} 启动成功, pid: {child_pid}", container_info.id); } Err(e) => { // clone 之后的错误 这里已经无法捕获了 println!("run_container失败: {e}"); let is_remove = args.restart.is_none(); - stop_container(&container_id, is_remove)?; + stop_container(&container_info.id, is_remove)?; } } } @@ -707,7 +683,12 @@ fn main() -> Result<()>{ stop_container(containers_id, false)?; } else if let (Some(cmd), Some(container_id)) = (&args.run, &args.exec) { // --exec - run_container(container_id, &cmd, &args, &Default::default(), true).unwrap(); + let container_info = get_container_info(container_id).unwrap(); + if container_info.status == ContainerStatus::RUNNING { + run_container(&container_info, Some(cmd)).unwrap(); + } else { + println!("容器{container_id}未运行"); + } } Ok(()) diff --git a/src/network.rs b/src/network.rs index bea51f8..0106d3d 100644 --- a/src/network.rs +++ b/src/network.rs @@ -489,7 +489,7 @@ pub fn remove_network(uuid_name: &str) { fn main(){ let container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string(); // create_network(&container_id, 2084); - remove_network("c3a20664"); + // remove_network("c3a20664"); }