restart 完成

main
阳光少年 1 year ago
parent d388e4e18b
commit 5c341af5f6

@ -65,7 +65,11 @@ struct RockerArgs {
// stop "container_id_1, container_id_2, container_id_3" // stop "container_id_1, container_id_2, container_id_3"
#[arg(long)] #[arg(long)]
stop: Option<String> stop: Option<String>,
// start container_id_1
#[arg(long)]
restart: Option<String>,
} }
@ -354,7 +358,6 @@ fn start(is_wait: bool, cb: CloneCb, clong_flags: CloneFlags) -> Result<i32>{
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_id: &String, cmd: &String, args: &RockerArgs, volume_path: &PathBuf, is_exec: bool) -> Result<i32> {
@ -435,8 +438,8 @@ impl Display for ContainerStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::READY => write!(f, "😀"), Self::READY => write!(f, "😀"),
Self::RUNNING => write!(f, ""), Self::RUNNING => write!(f, "🟢"),
Self::STOP => write!(f, ""), Self::STOP => write!(f, "🔴"),
} }
} }
@ -452,6 +455,7 @@ struct ContainerInfo {
volume: String, // /root/tmp:/root/tmp,/root/tmp1:/root/tmp1 volume: String, // /root/tmp:/root/tmp,/root/tmp1:/root/tmp1
env: String, // a=1,b=2,c=3 或者 env文件路径 env: String, // a=1,b=2,c=3 或者 env文件路径
status: ContainerStatus, status: ContainerStatus,
log: bool
} }
impl Display for ContainerInfo { impl Display for ContainerInfo {
@ -472,6 +476,7 @@ fn save_container_info(args: &RockerArgs, container_id: &String, pid: i32) -> Re
volume: args.volume.clone().unwrap_or("".to_string()), volume: args.volume.clone().unwrap_or("".to_string()),
env: args.env.clone().unwrap_or("".to_string()), env: args.env.clone().unwrap_or("".to_string()),
status: ContainerStatus::READY, status: ContainerStatus::READY,
log: args.log,
}; };
let toml_str = toml::to_string(&container_info)?; let toml_str = toml::to_string(&container_info)?;
fs::write(container_info_path, toml_str)?; fs::write(container_info_path, toml_str)?;
@ -534,9 +539,9 @@ 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(" ") {
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");
if let Ok(container_info) = get_container_info(container_id) {
println!("container_merged_path: {container_merged_path:?}"); println!("container_merged_path: {container_merged_path:?}");
// 正在运行中的需要 kill // 正在运行中的需要 kill
if container_info.status == ContainerStatus::RUNNING { if container_info.status == ContainerStatus::RUNNING {
@ -580,31 +585,79 @@ fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> {
} }
} }
} else { } else {
println!("容器不存在: {container_id}") println!("容器不存在: {container_id}, 尝试删除");
// todo 需要强制删除一下目录
match fs::remove_dir_all(container_work_path) {
Ok(_) => println!("删除容器 {container_id} 成功"),
Err(e) => println!("删除容器失败: {e:?}"),
}
} }
} }
Ok(()) Ok(())
} }
fn main() -> Result<()>{ fn main() -> Result<()>{
let args = RockerArgs::parse(); let mut args = RockerArgs::parse();
if let (Some(cmd), Some(image_name)) = (&args.run, &args.image) { if args.image.is_some() || args.restart.is_some() {
// run let volume_path;
let volume_path = extend_image(image_name)?; let container_id;
let container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string(); let cmd;
let mut pid = -1; match (&args.run, &args.image, &args.restart) {
match run_container(&container_id,&cmd, &args, &volume_path, false) { (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();
}
(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)?;
}
_ => {
unreachable!()
}
}
match run_container(&container_id, &cmd, &args, &volume_path, false) {
Ok(child_pid) => { Ok(child_pid) => {
pid = child_pid; save_container_info(&args, &container_id, child_pid)?;
} }
Err(e) => { Err(e) => {
// clone 之后的错误 这里已经无法捕获了
println!("run_container失败: {e}"); println!("run_container失败: {e}");
} let is_remove = args.restart.is_none();
} stop_container(&container_id, is_remove)?;
save_container_info(&args, &container_id, pid)?; // todo 无论出不错, 都要保存一个信息, 后面需要删除用清理 }
} else if args.ps || args.psa { }
}
// if let (Some(cmd), Some(image_name)) = (&args.run, &args.image) {
// // run
// let volume_path = extend_image(image_name)?;
// let container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string();
// match run_container(&container_id, &cmd, &args, &volume_path, false) {
// Ok(child_pid) => {
// save_container_info(&args, &container_id, child_pid)?;
// }
// Err(e) => {
// // clone 之后的错误 这里已经无法捕获了
// println!("run_container失败: {e}");
// stop_container(&container_id, true)?;
// }
// }
// }
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 {
@ -614,6 +667,7 @@ fn main() -> Result<()>{
// --stop // --stop
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
run_container(container_id, &cmd, &args, &Default::default(), true).unwrap(); run_container(container_id, &cmd, &args, &Default::default(), true).unwrap();
} }

@ -1,6 +1,8 @@
use std::{fs::OpenOptions, io::Read, os::unix::net}; use std::{fs::OpenOptions, io::Read};
use rand::Rng; use rand::Rng;
static NETWORK_FILE: &str = "/home/rocker/network";
fn get_gateway_addr(addr: &str) -> String { fn get_gateway_addr(addr: &str) -> String {
let prefix = &addr[..addr.len() - 1]; let prefix = &addr[..addr.len() - 1];
format!("{}0", prefix) format!("{}0", prefix)
@ -8,75 +10,75 @@ fn get_gateway_addr(addr: &str) -> String {
fn create_bridge_dev(bridge_name: &str) { fn create_bridge_dev(bridge_name: &str) {
// brctl addbr br0 // brctl addbr br0
let args = ["addbr", bridge_name]; let args = ["addbr", bridge_name];
println!("create_bridge_dev: {args:?}");
let out = std::process::Command::new("brctl") let out = std::process::Command::new("brctl")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("create_bridge_dev: {args:?}");
println!("{:?}", out);
} }
} }
fn set_bridge_ip(bridge_name: &str, addr: &str){ fn set_bridge_ip(bridge_name: &str, addr: &str){
// 设置容器内从ip: ip addr add 192.168.124.1/24 dev bridge_name // 设置容器内从ip: ip addr add 192.168.124.1/24 dev bridge_name
let args = ["addr", "add", &format!("{addr}/24"), "dev", bridge_name]; let args = ["addr", "add", &format!("{addr}/24"), "dev", bridge_name];
println!("set_bridge_ip: {args:?}");
let out = std::process::Command::new("ip") let out = std::process::Command::new("ip")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("set_bridge_ip: {args:?}");
println!("{:?}", out);
} }
} }
fn set_slave_ip(slave_veth_name: &str, addr: &str, pid: &str) { fn set_slave_ip(slave_veth_name: &str, addr: &str, pid: &str) {
// nsenter -t 10050 -n -- ip addr add <ip_address>/<subnet_mask> dev veth1 // nsenter -t 10050 -n -- ip addr add <ip_address>/<subnet_mask> dev veth1
let args = ["-t", pid, "-n", "--", "ip", "addr", "add", &format!("{addr}/24"), "dev", slave_veth_name]; let args = ["-t", pid, "-n", "--", "ip", "addr", "add", &format!("{addr}/24"), "dev", slave_veth_name];
println!("set_slave_ip: {args:?}");
let out = std::process::Command::new("nsenter") let out = std::process::Command::new("nsenter")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("set_slave_ip: {args:?}");
println!("{:?}", out);
} }
} }
fn set_snat(gateway_addr: &str, bridge_name: &str) { fn set_snat(gateway_addr: &str, bridge_name: &str) {
// sudo iptables -t nat -A POSTROUTING -s 172.18.0.0/24 ! -o br0 -j MASQUERADE // sudo iptables -t nat -A POSTROUTING -s 172.18.0.0/24 ! -o br0 -j MASQUERADE
let args = ["-t", "nat", "-A", "POSTROUTING", "-s", &format!("{gateway_addr}/24"), "!", "-o", bridge_name, "-j", "MASQUERADE"]; let args = ["-t", "nat", "-A", "POSTROUTING", "-s", &format!("{gateway_addr}/24"), "!", "-o", bridge_name, "-j", "MASQUERADE"];
println!("set_snat: {args:?}");
let out = std::process::Command::new("iptables") let out = std::process::Command::new("iptables")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("set_snat: {args:?}");
println!("{:?}", out);
} }
} }
fn set_iptables_forward() { fn set_iptables_forward() {
// sudo sysctl net.ipv4.conf.all.forwarding=1 // sudo sysctl net.ipv4.conf.all.forwarding=1
let args = ["net.ipv4.conf.all.forwarding=1"]; let args = ["net.ipv4.conf.all.forwarding=1"];
println!("set_iptables_forward: {args:?}");
let out = std::process::Command::new("sysctl") let out = std::process::Command::new("sysctl")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("set_iptables_forward: {args:?}");
println!("{:?}", out);
} }
// sudo iptables -t filter -P FORWARD ACCEPT // sudo iptables -t filter -P FORWARD ACCEPT
let args = ["-t", "filter", "-P", "FORWARD", "ACCEPT"]; let args = ["-t", "filter", "-P", "FORWARD", "ACCEPT"];
println!("set_iptables_forward: {args:?}");
let out = std::process::Command::new("iptables") let out = std::process::Command::new("iptables")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("set_iptables_forward: {args:?}");
println!("{:?}", out);
} }
} }
@ -84,58 +86,58 @@ fn set_iptables_forward() {
fn set_slave_route(slave_veth_name: &str, bridge_addr: &str, pid: &str) { fn set_slave_route(slave_veth_name: &str, bridge_addr: &str, pid: &str) {
// sudo nsenter -t 1851 -n -- ip route add default via 172.18.0.1 dev veth3 // sudo nsenter -t 1851 -n -- ip route add default via 172.18.0.1 dev veth3
let args = ["-t", pid, "-n", "--", "ip", "route", "add", "default", "via", bridge_addr, "dev", slave_veth_name]; let args = ["-t", pid, "-n", "--", "ip", "route", "add", "default", "via", bridge_addr, "dev", slave_veth_name];
println!("set_slave_route: {args:?}");
let out = std::process::Command::new("nsenter") let out = std::process::Command::new("nsenter")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("set_slave_route: {args:?}");
println!("{:?}", out);
} }
} }
fn set_net_up(bridge_name: &str, master_veth_name: &str, pid: &str, slave_veth_name: &str) { fn set_net_up(bridge_name: &str, master_veth_name: &str, pid: &str, slave_veth_name: &str) {
// sudo ip link set bridge_name up // sudo ip link set bridge_name up
let args = ["link", "set", bridge_name, "up"]; let args = ["link", "set", bridge_name, "up"];
println!("set_up: {args:?}");
let out = std::process::Command::new("ip") let out = std::process::Command::new("ip")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("set_up: {args:?}");
println!("{:?}", out);
} }
// sudo ip link set master_veth_name up // sudo ip link set master_veth_name up
let args = ["link", "set", master_veth_name, "up"]; let args = ["link", "set", master_veth_name, "up"];
println!("set_up: {args:?}");
let out = std::process::Command::new("ip") let out = std::process::Command::new("ip")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
println!("set_up: {args:?}");
println!("{:?}", out); println!("{:?}", out);
} }
// nsenter -t 1970 -n -- ip link set dev slave_veth_name up // nsenter -t 1970 -n -- ip link set dev slave_veth_name up
let args = ["-t", pid, "-n", "--", "ip", "link", "set", "dev", slave_veth_name, "up"]; let args = ["-t", pid, "-n", "--", "ip", "link", "set", "dev", slave_veth_name, "up"];
println!("set_up: {args:?}");
let out = std::process::Command::new("nsenter") let out = std::process::Command::new("nsenter")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
println!("set_up: {args:?}");
println!("{:?}", out); println!("{:?}", out);
} }
// ip link set lo up // ip link set lo up
let args = ["-t", pid, "-n", "--", "ip", "link", "set", "lo", "up"]; let args = ["-t", pid, "-n", "--", "ip", "link", "set", "lo", "up"];
println!("set_up: {args:?}");
let out = std::process::Command::new("nsenter") let out = std::process::Command::new("nsenter")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
println!("set_up: {args:?}");
println!("{:?}", out); println!("{:?}", out);
} }
} }
@ -211,20 +213,19 @@ fn del_bridge(bridge_name: &str) {
fn create_veth_pair(master_veth_name: &str, slave_veth_name: &str) { fn create_veth_pair(master_veth_name: &str, slave_veth_name: &str) {
// sudo ip link add master_veth_name type veth peer name slave_veth_name // sudo ip link add master_veth_name type veth peer name slave_veth_name
let args = ["link", "add", master_veth_name, "type", "veth", "peer", "name", slave_veth_name]; let args = ["link", "add", master_veth_name, "type", "veth", "peer", "name", slave_veth_name];
println!("create_veth_pair: {args:?}");
let out = std::process::Command::new("ip") let out = std::process::Command::new("ip")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("create_veth_pair: {args:?}");
println!("{:?}", out);
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
struct NetWrok { struct NetWrok {
gateway_addr: String, // 192.168.124.0 gateway_addr: String, // 192.168.124.0
bridge_addr: String, // 192.168.124.1 bridge_addr: String, // 192.168.124.1
@ -236,12 +237,12 @@ struct NetWrok {
} }
fn get_all_network() -> Vec<NetWrok> { fn get_all_network() -> Vec<NetWrok> {
// 打开 /home/rocker/network 所有已经配置的信息, 如果没有则创建 // 打开 NETWORK_FILE 所有已经配置的信息, 如果没有则创建
let mut f = OpenOptions::new() let mut f = OpenOptions::new()
.write(true) .write(true)
.create(true) .create(true)
.read(true) .read(true)
.open("/home/rocker/network") .open(NETWORK_FILE)
.unwrap(); .unwrap();
let mut text = String::new(); let mut text = String::new();
f.read_to_string(&mut text).unwrap(); f.read_to_string(&mut text).unwrap();
@ -252,13 +253,13 @@ fn master_join_bridge(bridge_name: &str, master_veth_name: &str) {
// 将主端链接到桥 // 将主端链接到桥
//sudo brctl addif bridge_name master_veth_name //sudo brctl addif bridge_name master_veth_name
let args = ["addif", bridge_name, master_veth_name]; let args = ["addif", bridge_name, master_veth_name];
println!("master_join_bridge: {args:?}");
let out = std::process::Command::new("brctl") let out = std::process::Command::new("brctl")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("master_join_bridge: {args:?}");
println!("{:?}", out);
} }
} }
@ -266,25 +267,24 @@ fn slave_join_bridge(slave_veth_name: &str, pid: &str) {
// 将从端 链接到容器 // 将从端 链接到容器
// sudo ip link set slave_veth_name netns 1234 // sudo ip link set slave_veth_name netns 1234
let args = ["link", "set", slave_veth_name, "netns", pid]; let args = ["link", "set", slave_veth_name, "netns", pid];
println!("slave_join_bridge: {args:?}");
let out = std::process::Command::new("ip") let out = std::process::Command::new("ip")
.args(args) .args(args)
.output() .output()
.unwrap(); .unwrap();
if !out.status.success() { if !out.status.success() {
panic!("{:?}", out); println!("slave_join_bridge: {args:?}");
println!("{:?}", out);
} }
} }
fn create_network(uuid_name: &str, pid: i32) { fn create_network(uuid_name: &str, pid: i32) {
// 创建一个随机地址段的 没分配过的ip // 创建一个随机地址段的 没分配过的ip
let all_network = get_all_network(); let mut all_network = get_all_network();
let mut rg = rand::thread_rng(); let mut rg = rand::thread_rng();
let network = loop { let network = loop {
// 生成一个随机桥ip // 生成一个随机桥ip
let base_addr = format!("{}.{}.{}", rg.gen_range(150..190), rg.gen_range(150..190), rg.gen_range(150..190)); let base_addr = format!("10.{}.{}", rg.gen_range(0..255), rg.gen_range(0..255));
let gateway_addr = format!("{base_addr}.0"); let gateway_addr = format!("{base_addr}.0");
let bridge_addr = format!("{base_addr}.1"); let bridge_addr = format!("{base_addr}.1");
let slave_addr = format!("{base_addr}.3"); let slave_addr = format!("{base_addr}.3");
@ -305,6 +305,8 @@ fn create_network(uuid_name: &str, pid: i32) {
} }
}; };
all_network.push(network.clone());
// 写入到文件中
let line = format!("{},{},{},{},{},{}", network.gateway_addr, network.bridge_addr, network.slave_addr, network.bridge_name, network.master_veth_name, network.slave_veth_name); let line = format!("{},{},{},{},{},{}", network.gateway_addr, network.bridge_addr, network.slave_addr, network.bridge_name, network.master_veth_name, network.slave_veth_name);
println!("{line:?}"); println!("{line:?}");
@ -330,31 +332,21 @@ fn create_network(uuid_name: &str, pid: i32) {
// 设置snat // 设置snat
set_snat(&network.gateway_addr, &network.bridge_name); set_snat(&network.gateway_addr, &network.bridge_name);
// 如果出错, 清理资源
}
fn remove_network(uuid_name: &str,) {
let bridge_name = format!("ro_{uuid_name}_1");
let master_veth_name = format!("ro_{uuid_name}_2");
let slave_veth_name = format!("ro_{uuid_name}_3");
//
let mut all_network = get_all_network();
// 删除 bridge_name 对应的 NetWork
all_network.retain(|n|n.bridge_name != bridge_name);
// todo 回写到文件中
// // 创建veth pair
// create_veth_pair(&network.master_veth_name, &network.slave_veth_name);
// // 把从 pair 添加到容器内
// slave_join_bridge(&network.slave_veth_name, pid.to_string().as_str());
// // 系统中创建桥
// create_bridge_dev(&network.bridge_name);
// // 宿主机 主pair 连接桥
// master_join_bridge(&network.bridge_name, &network.master_veth_name);
// // 给桥分配ip
// set_bridge_ip(&network.bridge_name, &network.bridge_addr);
// // 给容器内 pair 分配ip
// set_slave_ip(&network.slave_veth_name, &network.slave_addr, pid.to_string().as_str());
// // 激活 上线
// set_net_up(&network.bridge_name, &network.master_veth_name, pid.to_string().as_str(), &&network.slave_veth_name);
// // 配置路由
// let mut f = OpenOptions::new()
// .write(true)
// .create(true)
// .read(true)
// .open("/home/rocker/network")
// .unwrap();
} }

Loading…
Cancel
Save