2023-08-26 22:32:38 +02:00
|
|
|
use churn_domain::{AgentEnrollReq, LeaseResp, ServerMonitorResp};
|
2023-08-24 17:22:45 +02:00
|
|
|
use clap::{Parser, Subcommand};
|
|
|
|
|
|
|
|
#[derive(Parser)]
|
|
|
|
#[command(author, version, about, long_about = None, subcommand_required = true)]
|
|
|
|
struct Command {
|
|
|
|
#[command(subcommand)]
|
|
|
|
command: Option<Commands>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subcommand)]
|
|
|
|
enum Commands {
|
2023-08-26 22:32:38 +02:00
|
|
|
Auth {
|
|
|
|
#[arg(env = "CHURN_SERVER", long)]
|
|
|
|
server: String,
|
|
|
|
|
|
|
|
#[arg(env = "CHURN_SERVER_TOKEN", long)]
|
|
|
|
server_token: String,
|
|
|
|
},
|
2023-08-24 17:22:45 +02:00
|
|
|
Bootstrap {
|
|
|
|
#[arg(env = "CHURN_AGENT", long)]
|
2023-08-26 19:31:54 +02:00
|
|
|
agent: String,
|
2023-08-24 17:22:45 +02:00
|
|
|
|
2023-08-26 22:32:38 +02:00
|
|
|
#[arg(env = "CHURN_AGENT_NAME", long)]
|
|
|
|
agent_name: String,
|
|
|
|
|
2023-08-24 17:22:45 +02:00
|
|
|
#[arg(env = "CHURN_SERVER", long)]
|
|
|
|
server: String,
|
|
|
|
|
|
|
|
#[arg(env = "CHURN_SERVER_TOKEN", long)]
|
|
|
|
server_token: String,
|
|
|
|
},
|
|
|
|
Health {
|
|
|
|
#[arg(env = "CHURN_SERVER", long)]
|
|
|
|
server: String,
|
|
|
|
#[arg(env = "CHURN_AGENT", long)]
|
|
|
|
agent: String,
|
|
|
|
},
|
2023-08-26 22:32:38 +02:00
|
|
|
Monitor {
|
|
|
|
#[arg(env = "CHURN_SERVER", long)]
|
|
|
|
server: String,
|
|
|
|
|
|
|
|
#[arg(env = "CHURN_SERVER_TOKEN", long)]
|
|
|
|
server_token: String,
|
|
|
|
},
|
2023-08-24 17:22:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() -> anyhow::Result<()> {
|
|
|
|
dotenv::dotenv().ok();
|
|
|
|
tracing_subscriber::fmt::init();
|
|
|
|
|
|
|
|
let cli = Command::parse();
|
|
|
|
|
|
|
|
handle_command(cli).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_command(cmd: Command) -> anyhow::Result<()> {
|
|
|
|
if let Some(cmd) = cmd.command {
|
|
|
|
match cmd {
|
|
|
|
Commands::Bootstrap {
|
2023-08-26 19:31:54 +02:00
|
|
|
agent,
|
2023-08-26 22:32:38 +02:00
|
|
|
agent_name,
|
2023-08-24 17:22:45 +02:00
|
|
|
server,
|
2023-08-26 22:32:38 +02:00
|
|
|
server_token: _,
|
|
|
|
} => {
|
|
|
|
tracing::info!("enrolling agent: {} for server: {}", agent, server);
|
|
|
|
let client = reqwest::Client::new();
|
|
|
|
let req = client.post(format!("{server}/agent/lease")).build()?;
|
|
|
|
let lease_resp = client.execute(req).await?;
|
|
|
|
let lease = lease_resp.json::<LeaseResp>().await?;
|
|
|
|
|
|
|
|
let req = client
|
|
|
|
.post(format!("{agent}/enroll"))
|
|
|
|
.json(&AgentEnrollReq {
|
|
|
|
lease: lease.token,
|
|
|
|
server,
|
|
|
|
agent_name,
|
|
|
|
})
|
|
|
|
.build()?;
|
|
|
|
let lease_resp = client.execute(req).await?;
|
|
|
|
if !lease_resp.status().is_success() {
|
|
|
|
if let Ok(text) = lease_resp.text().await {
|
|
|
|
tracing::warn!(
|
|
|
|
"could not enroll because agent server encoutered error: {}",
|
|
|
|
text
|
|
|
|
);
|
|
|
|
anyhow::bail!("encountered error: {}", text);
|
|
|
|
}
|
|
|
|
anyhow::bail!("encountered error");
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2023-08-24 17:22:45 +02:00
|
|
|
Commands::Health { server, agent } => {
|
|
|
|
tracing::info!("connecting to server: {}", server);
|
2023-08-25 21:52:28 +02:00
|
|
|
reqwest::get(format!("{server}/ping")).await?;
|
|
|
|
tracing::info!("connected to server successfully");
|
2023-08-24 17:22:45 +02:00
|
|
|
tracing::info!("connecting to agent: {}", agent);
|
2023-08-25 21:52:28 +02:00
|
|
|
reqwest::get(format!("{agent}/ping")).await?;
|
|
|
|
tracing::info!("connected to agent successfully");
|
2023-08-24 17:22:45 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
2023-08-26 22:32:38 +02:00
|
|
|
Commands::Auth {
|
|
|
|
server: _,
|
|
|
|
server_token: _,
|
|
|
|
} => todo!(),
|
|
|
|
Commands::Monitor {
|
|
|
|
server,
|
2023-08-27 19:42:33 +02:00
|
|
|
server_token: _,
|
2023-08-26 22:32:38 +02:00
|
|
|
} => {
|
|
|
|
tracing::info!("monitoring server: {}", server);
|
|
|
|
|
2023-08-27 00:07:56 +02:00
|
|
|
let mut cursor: Option<uuid::Uuid> = None;
|
2023-08-26 22:32:38 +02:00
|
|
|
loop {
|
2023-08-27 00:07:56 +02:00
|
|
|
tracing::debug!("reading logs from server: {}", server);
|
2023-08-26 22:32:38 +02:00
|
|
|
|
|
|
|
let resp = reqwest::get(format!(
|
|
|
|
"{server}/logs{}",
|
|
|
|
match &cursor {
|
|
|
|
None => "".to_string(),
|
|
|
|
Some(cursor) => format!("?cursor={}", cursor),
|
|
|
|
}
|
|
|
|
))
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
if !resp.status().is_success() {
|
|
|
|
if let Ok(text) = resp.text().await {
|
|
|
|
anyhow::bail!("encountered error: {}", text);
|
|
|
|
}
|
|
|
|
anyhow::bail!("encountered error");
|
|
|
|
}
|
|
|
|
|
|
|
|
match resp.json::<ServerMonitorResp>().await {
|
|
|
|
Ok(resp) => {
|
|
|
|
for line in resp.logs {
|
2023-08-27 00:07:56 +02:00
|
|
|
tracing::info!("event: {}", line);
|
2023-08-26 22:32:38 +02:00
|
|
|
}
|
2023-08-27 00:07:56 +02:00
|
|
|
cursor = resp.cursor;
|
2023-08-26 22:32:38 +02:00
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
tracing::warn!("failed to call server (error={})", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
|
|
|
}
|
|
|
|
}
|
2023-08-24 17:22:45 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
panic!("no command supplied")
|
|
|
|
}
|
|
|
|
}
|