|
|
|
@ -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(){
|
|
|
|
|
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::<Vec<String>>()
|
|
|
|
|
} else {
|
|
|
|
|
env.split(",").map(String::from).collect::<Vec<String>>()
|
|
|
|
|
};
|
|
|
|
|
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::<Vec<String>>()
|
|
|
|
|
} 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() {
|
|
|
|
|
let item_env_v = item_env.split("=").collect::<Vec<&str>>();
|
|
|
|
|
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<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)} {
|
|
|
|
|
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<i32> {
|
|
|
|
|
fn run_container(container_info: &ContainerInfo, is_exec_cmd: Option<&String>) -> Result<i32> {
|
|
|
|
|
// 禁止同时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::<Vec<&str>>();
|
|
|
|
|
let cmd_vec = exec_cmd.split(" ").collect::<Vec<&str>>();
|
|
|
|
|
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::<Vec<&str>>();
|
|
|
|
|
let cmd_vec = container_info.run.split(" ").collect::<Vec<&str>>();
|
|
|
|
|
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(())
|
|
|
|
|