feat(install): add --container-only flag to install command
- Add --container-only flag to create container without completing full installation - Exit immediately after container creation - Useful for manual setup or debugging installation issues
This commit is contained in:
parent
d1cb6b758c
commit
dfe5162f66
2 changed files with 88 additions and 4 deletions
|
|
@ -84,7 +84,7 @@ pub async fn run() -> Result<()> {
|
||||||
}
|
}
|
||||||
"install" => {
|
"install" => {
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
eprintln!("Usage: botserver install <component> [--container] [--tenant <name>]");
|
eprintln!("Usage: botserver install <component> [--container] [--container-only] [--tenant <name>]");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let component = &args[2];
|
let component = &args[2];
|
||||||
|
|
@ -99,17 +99,26 @@ pub async fn run() -> Result<()> {
|
||||||
} else {
|
} else {
|
||||||
InstallMode::Local
|
InstallMode::Local
|
||||||
};
|
};
|
||||||
|
let container_only = args.contains(&"--container-only".to_string());
|
||||||
let tenant = if let Some(idx) = args.iter().position(|a| a == "--tenant") {
|
let tenant = if let Some(idx) = args.iter().position(|a| a == "--tenant") {
|
||||||
args.get(idx + 1).cloned()
|
args.get(idx + 1).cloned()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let pm = PackageManager::new(mode, tenant)?;
|
let pm = PackageManager::new(mode.clone(), tenant)?;
|
||||||
let result = pm.install(component).await?;
|
|
||||||
println!("* Component '{}' installed successfully", component);
|
let result = if container_only && mode == InstallMode::Container {
|
||||||
|
Some(pm.install_container_only(component)?)
|
||||||
|
} else {
|
||||||
|
pm.install(component).await?
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(install_result) = result {
|
if let Some(install_result) = result {
|
||||||
install_result.print();
|
install_result.print();
|
||||||
|
if container_only {
|
||||||
|
println!("\n* Container created successfully (--container-only mode)");
|
||||||
|
println!("* Run without --container-only to complete installation");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"remove" => {
|
"remove" => {
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,72 @@ impl PackageManager {
|
||||||
self.run_commands(post_cmds, "local", &component.name)?;
|
self.run_commands(post_cmds, "local", &component.name)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
pub fn install_container_only(&self, component_name: &str) -> Result<InstallResult> {
|
||||||
|
let container_name = format!("{}-{}", self.tenant, component_name);
|
||||||
|
|
||||||
|
let _ = safe_lxd(&["init", "--auto"]);
|
||||||
|
|
||||||
|
let images = [
|
||||||
|
"ubuntu:24.04",
|
||||||
|
"ubuntu:22.04",
|
||||||
|
"images:debian/12",
|
||||||
|
"images:debian/11",
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut last_error = String::new();
|
||||||
|
let mut success = false;
|
||||||
|
|
||||||
|
for image in &images {
|
||||||
|
info!("Attempting to create container with image: {}", image);
|
||||||
|
let output = safe_lxc(&[
|
||||||
|
"launch",
|
||||||
|
image,
|
||||||
|
&container_name,
|
||||||
|
"-c",
|
||||||
|
"security.privileged=true",
|
||||||
|
]);
|
||||||
|
|
||||||
|
let output = match output {
|
||||||
|
Some(o) => o,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if output.status.success() {
|
||||||
|
info!("Successfully created container with image: {}", image);
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_error = String::from_utf8_lossy(&output.stderr).to_string();
|
||||||
|
warn!("Failed to create container with {}: {}", image, last_error);
|
||||||
|
|
||||||
|
let _ = safe_lxc(&["delete", &container_name, "--force"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !success {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"LXC container creation failed with all images. Last error: {}",
|
||||||
|
last_error
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_secs(15));
|
||||||
|
|
||||||
|
let container_ip = Self::get_container_ip(&container_name)?;
|
||||||
|
|
||||||
|
info!("Container '{}' created successfully at IP: {}", container_name, container_ip);
|
||||||
|
|
||||||
|
Ok(InstallResult {
|
||||||
|
component: component_name.to_string(),
|
||||||
|
container_name: container_name.clone(),
|
||||||
|
container_ip: container_ip.clone(),
|
||||||
|
ports: vec![],
|
||||||
|
env_vars: std::collections::HashMap::new(),
|
||||||
|
connection_info: format!(
|
||||||
|
"Container '{}' created successfully at IP: {}\nRun without --container-only to complete installation.",
|
||||||
|
container_name, container_ip
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
pub fn install_container(&self, component: &ComponentConfig) -> Result<InstallResult> {
|
pub fn install_container(&self, component: &ComponentConfig) -> Result<InstallResult> {
|
||||||
let container_name = format!("{}-{}", self.tenant, component.name);
|
let container_name = format!("{}-{}", self.tenant, component.name);
|
||||||
|
|
||||||
|
|
@ -216,6 +282,15 @@ impl PackageManager {
|
||||||
"mkdir -p /opt/gbo/bin /opt/gbo/data /opt/gbo/conf /opt/gbo/logs",
|
"mkdir -p /opt/gbo/bin /opt/gbo/data /opt/gbo/conf /opt/gbo/logs",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
self.exec_in_container(
|
||||||
|
&container_name,
|
||||||
|
"echo 'nameserver 8.8.8.8' > /etc/resolv.conf",
|
||||||
|
)?;
|
||||||
|
self.exec_in_container(
|
||||||
|
&container_name,
|
||||||
|
"echo 'nameserver 8.8.4.4' >> /etc/resolv.conf",
|
||||||
|
)?;
|
||||||
|
|
||||||
self.exec_in_container(&container_name, "apt-get update -qq")?;
|
self.exec_in_container(&container_name, "apt-get update -qq")?;
|
||||||
self.exec_in_container(
|
self.exec_in_container(
|
||||||
&container_name,
|
&container_name,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue