Skip to content

Commit 30552cb

Browse files
Print root password when provisioning Hetzner server
The Hetzner API returns a root_password when creating a server without SSH keys. Now we capture and print this to the terminal so users can SSH into the machine for debugging. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ba83a5b commit 30552cb

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

src/hetzner.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ struct CreateServerRequest {
8888
#[derive(Debug, Deserialize)]
8989
struct CreateServerResponse {
9090
server: Server,
91+
root_password: Option<String>,
92+
}
93+
94+
/// Result of creating a server, includes the server info and root password
95+
pub struct CreateServerResult {
96+
pub server: Server,
97+
pub root_password: Option<String>,
9198
}
9299

93100
#[allow(dead_code)]
@@ -115,7 +122,7 @@ impl HetznerClient {
115122
}
116123
}
117124

118-
pub async fn create_server(&self, config: &ServerConfig) -> Result<Server> {
125+
pub async fn create_server(&self, config: &ServerConfig) -> Result<CreateServerResult> {
119126
let url = format!("{}/servers", HETZNER_API_BASE);
120127

121128
let labels = if config.labels.is_empty() {
@@ -186,7 +193,10 @@ impl HetznerClient {
186193
result.server.name, result.server.id, result.server.public_net.ipv4.ip
187194
);
188195

189-
Ok(result.server)
196+
Ok(CreateServerResult {
197+
server: result.server,
198+
root_password: result.root_password,
199+
})
190200
}
191201

192202
pub async fn delete_server(&self, id: u64) -> Result<()> {
@@ -503,13 +513,19 @@ final_message: "FFmpeg worker is ready!"
503513
)
504514
}
505515

516+
/// Result of provisioning a worker
517+
pub struct ProvisionResult {
518+
pub ip: String,
519+
pub root_password: Option<String>,
520+
}
521+
506522
pub async fn provision_worker(
507523
hetzner_token: &str,
508524
queue_url: &str,
509525
binary_url: &str,
510526
bg_image_url: &str,
511527
name: Option<String>,
512-
) -> Result<String> {
528+
) -> Result<ProvisionResult> {
513529
let client = HetznerClient::new(hetzner_token.to_string());
514530

515531
let name = name.unwrap_or_else(|| {
@@ -527,6 +543,9 @@ pub async fn provision_worker(
527543
..Default::default()
528544
};
529545

530-
let server = client.create_server(&config).await?;
531-
Ok(server.public_net.ipv4.ip)
546+
let result = client.create_server(&config).await?;
547+
Ok(ProvisionResult {
548+
ip: result.server.public_net.ipv4.ip,
549+
root_password: result.root_password,
550+
})
532551
}

src/hetzner_cli.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,18 @@ async fn main() -> Result<()> {
7777
let binary_url = format!("{}/assets/worker", base);
7878
let bg_image_url = format!("{}/assets/gpc-bg.png", base);
7979

80-
let ip = hetzner::provision_worker(
80+
let result = hetzner::provision_worker(
8181
&token,
8282
&queue_url,
8383
&binary_url,
8484
&bg_image_url,
8585
name,
8686
)
8787
.await?;
88-
println!("Worker provisioned at IP: {}", ip);
88+
println!("Worker provisioned at IP: {}", result.ip);
89+
if let Some(password) = result.root_password {
90+
println!("Root password: {}", password);
91+
}
8992
}
9093
Commands::ListServers { token } => {
9194
let client = hetzner::HetznerClient::new(token);

0 commit comments

Comments
 (0)