阳光少年 1 year ago
parent 8b6762dab0
commit e3888c4996

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

@ -489,7 +489,7 @@ pub fn remove_network(uuid_name: &str) {
fn main(){ fn main(){
let container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string(); let container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string();
// create_network(&container_id, 2084); // create_network(&container_id, 2084);
remove_network("c3a20664"); // remove_network("c3a20664");
} }

Loading…
Cancel
Save