mirror of
https://codeberg.org/spire/dispenser.git
synced 2026-06-03 18:14:06 +02:00
tracing
This commit is contained in:
parent
c2fd7cd3f8
commit
a581121bd6
5 changed files with 117 additions and 13 deletions
24
src/main.rs
24
src/main.rs
|
|
@ -14,6 +14,7 @@ use thiserror::Error;
|
|||
use tokio::select;
|
||||
use tokio::signal::ctrl_c;
|
||||
use tokio::time::sleep;
|
||||
use tracing::{debug, error, info, instrument, warn};
|
||||
|
||||
mod cloud;
|
||||
mod config;
|
||||
|
|
@ -41,18 +42,25 @@ pub enum Error {
|
|||
Rcon(#[from] ::rcon::Error),
|
||||
}
|
||||
|
||||
#[instrument(skip(config))]
|
||||
async fn setup(ssh: &mut SshSession, config: &ServerConfig) -> Result<(), Error> {
|
||||
let mut tries = 0;
|
||||
|
||||
debug!(image = display(&config.image), "pulling image");
|
||||
loop {
|
||||
tries += 1;
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
let result = ssh.exec("docker pull spiretf/docker-spire-server").await?;
|
||||
let result = ssh.exec(format!("docker pull {}", config.image)).await?;
|
||||
if result.success() {
|
||||
break;
|
||||
} else if tries > 5 {
|
||||
return Err(Error::SetupError(result.output()));
|
||||
} else {
|
||||
error!(tries = tries, "Failed to pull docker image, retrying");
|
||||
}
|
||||
}
|
||||
|
||||
debug!("starting container");
|
||||
let result = ssh
|
||||
.exec(format!(
|
||||
"docker run --name spire -d \
|
||||
|
|
@ -82,6 +90,7 @@ async fn setup(ssh: &mut SshSession, config: &ServerConfig) -> Result<(), Error>
|
|||
return Err(Error::SetupError(result.output()));
|
||||
}
|
||||
|
||||
debug!("setting up swap");
|
||||
ssh.exec("dd if=/dev/zero of=/swapfile bs=1M count=1024")
|
||||
.await?;
|
||||
ssh.exec("chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile")
|
||||
|
|
@ -91,7 +100,7 @@ async fn setup(ssh: &mut SshSession, config: &ServerConfig) -> Result<(), Error>
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
pretty_env_logger::init();
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let mut args = args();
|
||||
let bin = args.next().unwrap();
|
||||
|
|
@ -138,6 +147,10 @@ async fn run_loop(
|
|||
match start(cloud.as_ref(), &config).await {
|
||||
Ok(server) => active_server = Some(server),
|
||||
Err(Error::AlreadyRunning(server)) if config.server.manage_existing => {
|
||||
info!(
|
||||
server = debug(&server),
|
||||
"Taking ownership of existing server"
|
||||
);
|
||||
active_server = Some(server);
|
||||
}
|
||||
Err(e) => eprintln!("{:#}", e),
|
||||
|
|
@ -158,14 +171,14 @@ async fn run_loop(
|
|||
let stop = match active_players_res {
|
||||
Ok(0) => true,
|
||||
Ok(count) => {
|
||||
println!(
|
||||
info!(
|
||||
"Want to stop server, but there are still {} active players",
|
||||
count
|
||||
);
|
||||
false
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}", e);
|
||||
error!("Error while trying get player count: {}", e);
|
||||
true
|
||||
}
|
||||
};
|
||||
|
|
@ -185,12 +198,13 @@ async fn run_loop(
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(cloud, config))]
|
||||
async fn start(cloud: &dyn Cloud, config: &Config) -> Result<Server, Error> {
|
||||
let list = cloud.list().await?;
|
||||
let count = list.len();
|
||||
let first = list.into_iter().next();
|
||||
if let Some(first) = first {
|
||||
eprintln!(
|
||||
warn!(
|
||||
"Non empty server list while starting: {:?}, and {} more",
|
||||
first,
|
||||
count - 1
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
use crate::Error;
|
||||
use rcon::Connection;
|
||||
use std::fmt::Debug;
|
||||
use tokio::net::{TcpStream, ToSocketAddrs};
|
||||
use tracing::instrument;
|
||||
|
||||
pub struct Rcon(Connection<TcpStream>);
|
||||
|
||||
impl Rcon {
|
||||
pub async fn new<A: ToSocketAddrs>(host: A, password: &str) -> Result<Self, Error> {
|
||||
#[instrument(skip(password))]
|
||||
pub async fn new<A: ToSocketAddrs + Debug>(host: A, password: &str) -> Result<Self, Error> {
|
||||
Ok(Rcon(Connection::builder().connect(host, password).await?))
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn player_count(&mut self) -> Result<usize, Error> {
|
||||
let status = self.0.cmd("status").await?;
|
||||
let player_lines = status
|
||||
|
|
|
|||
29
src/ssh.rs
29
src/ssh.rs
|
|
@ -1,4 +1,5 @@
|
|||
use futures_util::future::{self};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::io::Write;
|
||||
use std::net::IpAddr;
|
||||
use std::sync::Arc;
|
||||
|
|
@ -8,6 +9,7 @@ use thrussh::client::Handle;
|
|||
use thrussh::*;
|
||||
use thrussh_keys::key::PublicKey;
|
||||
use tokio::time::{sleep, timeout};
|
||||
use tracing::instrument;
|
||||
|
||||
struct Client {}
|
||||
|
||||
|
|
@ -56,10 +58,20 @@ impl client::Handler for Client {
|
|||
}
|
||||
|
||||
pub struct SshSession {
|
||||
ip: IpAddr,
|
||||
handle: Handle<Client>,
|
||||
}
|
||||
|
||||
impl Debug for SshSession {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("SshSession")
|
||||
.field("ip", &format_args!("{}", self.ip))
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl SshSession {
|
||||
#[instrument(skip(password))]
|
||||
pub async fn open(ip: IpAddr, password: &str) -> Result<Self, SshError> {
|
||||
Ok(timeout(Duration::from_secs(5 * 60), async move {
|
||||
loop {
|
||||
|
|
@ -76,29 +88,33 @@ impl SshSession {
|
|||
}
|
||||
|
||||
async fn open_impl(ip: IpAddr, password: &str) -> Result<Self, SshError> {
|
||||
let config = thrussh::client::Config::default();
|
||||
let config = client::Config::default();
|
||||
let config = Arc::new(config);
|
||||
let sh = Client {};
|
||||
|
||||
let mut handle = thrussh::client::connect(config, (ip, 22), sh).await?;
|
||||
let mut handle = client::connect(config, (ip, 22), sh).await?;
|
||||
if handle.authenticate_password("root", password).await? {
|
||||
Ok(SshSession { handle })
|
||||
Ok(SshSession { ip, handle })
|
||||
} else {
|
||||
Err(SshError::Unauthorized)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn exec<S: Into<String>>(&mut self, cmd: S) -> Result<CommandResult, SshError> {
|
||||
#[instrument]
|
||||
pub async fn exec<S: Into<String> + Debug>(
|
||||
&mut self,
|
||||
cmd: S,
|
||||
) -> Result<CommandResult, SshError> {
|
||||
let mut channel = self.handle.channel_open_session().await?;
|
||||
channel.exec(true, cmd).await?;
|
||||
let mut output = Vec::new();
|
||||
let mut code = None;
|
||||
while let Some(msg) = channel.wait().await {
|
||||
match msg {
|
||||
thrussh::ChannelMsg::Data { ref data } => {
|
||||
ChannelMsg::Data { ref data } => {
|
||||
output.write_all(data).unwrap();
|
||||
}
|
||||
thrussh::ChannelMsg::ExitStatus { exit_status } => {
|
||||
ChannelMsg::ExitStatus { exit_status } => {
|
||||
code = Some(exit_status);
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -107,6 +123,7 @@ impl SshSession {
|
|||
Ok(CommandResult { output, code })
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn close(mut self) -> Result<(), SshError> {
|
||||
self.handle
|
||||
.disconnect(Disconnect::ByApplication, "", "English")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue