use monocore::{
config::{Group, Monocore, Service},
orchestration::{LogRetentionPolicy, Orchestrator},
utils,
};
use std::{net::Ipv4Addr, time::Duration};
use tokio::time;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.init();
let build_dir = format!("{}/build", env!("CARGO_MANIFEST_DIR"));
let oci_dir = format!("{}/oci", build_dir);
let rootfs_dir = format!("{}/rootfs", build_dir);
let image_ref = "library/alpine:latest";
let (_, _, rootfs_name) = utils::parse_image_ref(image_ref).unwrap();
let ref_rootfs_dir = format!("{}/reference/{}", rootfs_dir, rootfs_name);
utils::pull_docker_image(&oci_dir, image_ref).await?;
utils::merge_image_layers(&oci_dir, &ref_rootfs_dir, image_ref).await?;
println!("OCI directory: {}", oci_dir);
let supervisor_path = format!("{}/../target/release/monokrun", env!("CARGO_MANIFEST_DIR"));
let mut orchestrator = Orchestrator::with_log_retention_policy(
build_dir,
supervisor_path,
LogRetentionPolicy::with_max_age_weeks(1),
)
.await?;
let initial_config = create_initial_config()?;
println!("Starting initial services...");
orchestrator.up(initial_config).await?;
time::sleep(Duration::from_secs(10)).await;
print_service_status(&orchestrator).await?;
let updated_config = create_updated_config()?;
println!("\nUpdating services...");
orchestrator.up(updated_config).await?;
time::sleep(Duration::from_secs(10)).await;
print_service_status(&orchestrator).await?;
println!("\nStopping all services...");
orchestrator.down(None).await?;
Ok(())
}
async fn print_service_status(orchestrator: &Orchestrator) -> anyhow::Result<()> {
println!("\nCurrent Service Status:");
println!();
println!(
"{:<15} {:<10} {:<8} {:<8} {:<10} {:<10} {:<15} {:<15} {:<10} {:<10}",
"Service",
"Group",
"vCPUs",
"RAM",
"Sup PID",
"VM PID",
"Status",
"Assigned IP",
"CPU Usage",
"Mem Usage"
);
println!("{:-<120}", "");
let statuses = orchestrator.status().await?;
for status in statuses {
let sup_pid = orchestrator
.get_running_services()
.get(status.get_name())
.copied()
.unwrap_or(0);
let cpu_pct = (status.get_state().get_metrics().get_cpu_usage() * 100.0).ceil();
let mem_mib =
(status.get_state().get_metrics().get_memory_usage() as f64) / (1024.0 * 1024.0);
println!(
"{:<15} {:<10} {:<8} {:<8} {:<10} {:<10} {:<15} {:<15} {:<10} {:<10}",
status.get_name(),
status.get_state().get_group().get_name(),
status.get_state().get_service().get_cpus(),
status.get_state().get_service().get_ram(),
sup_pid,
status.get_pid().unwrap_or(0),
format!("{:?}", status.get_state().get_status()),
status
.get_state()
.get_group_ip()
.map_or_else(|| Ipv4Addr::LOCALHOST, |ip| ip),
format!("{}%", cpu_pct as u64),
format!("{}MiB", mem_mib.ceil() as u64)
);
}
println!();
Ok(())
}
fn create_initial_config() -> anyhow::Result<Monocore> {
let main_group = Group::builder().name("main").build();
let tail_service = Service::builder()
.name("tail-service")
.base("library/alpine:latest")
.ram(512)
.group("main")
.command("/usr/bin/tail")
.args(["-f", "/dev/null"])
.depends_on(["sleep-service".to_string()])
.build();
let sleep_service = Service::builder()
.name("sleep-service")
.base("library/alpine:latest")
.ram(512)
.group("main")
.command("/bin/sleep")
.args(["infinity"])
.build();
let config = Monocore::builder()
.services(vec![tail_service, sleep_service])
.groups(vec![main_group])
.build()?;
Ok(config)
}
fn create_updated_config() -> anyhow::Result<Monocore> {
let main_group = Group::builder().name("main").build();
let tail_service = Service::builder()
.name("tail-service")
.base("library/alpine:latest")
.ram(512)
.group("main")
.command("/usr/bin/tail")
.args(["-f", "/etc/hosts"]) .build();
let sleep_service = Service::builder()
.name("sleep-service")
.base("library/alpine:latest")
.ram(512)
.group("main")
.command("/bin/sleep")
.args(["infinity"])
.build();
let echo_service = Service::builder()
.name("echo-service")
.base("library/alpine:latest")
.ram(512)
.group("main")
.command("/bin/sh")
.args([
"-c",
"while true; do echo 'Hello from echo service'; sleep 5; done",
])
.build();
let config = Monocore::builder()
.services(vec![tail_service, sleep_service, echo_service])
.groups(vec![main_group])
.build()?;
Ok(config)
}