Skip to content

Commit 3ad59e9

Browse files
committed
move error codes to an enum propolis-api-types
1 parent 686d48b commit 3ad59e9

File tree

2 files changed

+60
-15
lines changed

2 files changed

+60
-15
lines changed

bin/propolis-server/src/lib/server.rs

+15-14
Original file line numberDiff line numberDiff line change
@@ -571,19 +571,21 @@ async fn instance_ensure_common(
571571
{
572572
let existing_properties = existing.properties();
573573
if existing_properties.id != properties.id {
574-
return Err(HttpError::for_status(
575-
Some(format!(
574+
return Err(HttpError::for_client_error(
575+
Some(api::ErrorCode::AlreadyInitialized.to_string()),
576+
http::status::StatusCode::CONFLICT,
577+
format!(
576578
"Server already initialized with ID {}",
577579
existing_properties.id
578-
)),
579-
http::status::StatusCode::CONFLICT,
580+
),
580581
));
581582
}
582583

583584
if *existing_properties != properties {
584-
return Err(HttpError::for_status(
585-
Some("Cannot update running server".to_string()),
585+
return Err(HttpError::for_client_error(
586+
Some(api::ErrorCode::AlreadyRunning.to_string()),
586587
http::status::StatusCode::CONFLICT,
588+
"Cannot update running server".to_string(),
587589
));
588590
}
589591

@@ -653,10 +655,11 @@ async fn instance_ensure_common(
653655
vm_hdl.await.unwrap()
654656
}
655657
.map_err(|e| {
656-
HttpError::for_internal_error(format!(
657-
"failed to create instance: {}",
658-
e
659-
))
658+
HttpError::for_client_error(
659+
Some(api::ErrorCode::CreateFailed.to_string()),
660+
http::status::StatusCode::INTERNAL_SERVER_ERROR,
661+
format!("failed to create instance: {e}"),
662+
)
660663
})?;
661664

662665
if let Some(ramfb) = vm.framebuffer() {
@@ -875,7 +878,7 @@ async fn instance_state_monitor(
875878
// Inform the client of this condition so it doesn't wait forever.
876879
state_watcher.changed().await.map_err(|_| {
877880
HttpError::for_client_error(
878-
Some(NO_INSTANCE.to_string()),
881+
Some(api::ErrorCode::NoInstance.to_string()),
879882
http::status::StatusCode::GONE,
880883
format!(
881884
"No instance present; will never reach generation {}",
@@ -1193,11 +1196,9 @@ pub fn api() -> ApiDescription<Arc<DropshotEndpointContext>> {
11931196
api
11941197
}
11951198

1196-
const NO_INSTANCE: &str = "NO_INSTANCE";
1197-
11981199
fn not_created_error() -> HttpError {
11991200
HttpError::for_client_error(
1200-
Some(NO_INSTANCE.to_string()),
1201+
Some(api::ErrorCode::NoInstance.to_string()),
12011202
http::StatusCode::FAILED_DEPENDENCY,
12021203
"Server not initialized (no instance)".to_string(),
12031204
)

crates/propolis-api-types/src/lib.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
//! Definitions for types exposed by the propolis-server API
66
7-
use std::net::SocketAddr;
7+
use std::{fmt, net::SocketAddr};
88

99
use schemars::JsonSchema;
1010
use serde::{Deserialize, Serialize};
@@ -395,3 +395,47 @@ pub struct SnapshotRequestPathParams {
395395
pub struct VCRRequestPathParams {
396396
pub id: Uuid,
397397
}
398+
399+
/// Error codes used to populate the `error_code` field of Dropshot API responses.
400+
#[derive(
401+
Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema,
402+
)]
403+
pub enum ErrorCode {
404+
/// This `propolis-server` process has not received an `InstanceEnsure`
405+
/// request yet.
406+
NoInstance,
407+
/// This `propolis-server` process has already received an `InstanceEnsure`
408+
/// request with a different ID.
409+
AlreadyInitialized,
410+
/// Cannot update a running server.
411+
AlreadyRunning,
412+
/// Instance creation failed
413+
CreateFailed,
414+
}
415+
416+
impl fmt::Display for ErrorCode {
417+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
418+
fmt::Debug::fmt(self, f)
419+
}
420+
}
421+
422+
impl std::str::FromStr for ErrorCode {
423+
type Err = &'static str;
424+
fn from_str(s: &str) -> Result<Self, Self::Err> {
425+
match s.trim() {
426+
s if s.eq_ignore_ascii_case("NoInstance") => Ok(Self::NoInstance),
427+
s if s.eq_ignore_ascii_case("AlreadyInitialized") => {
428+
Ok(ErrorCode::AlreadyInitialized)
429+
}
430+
s if s.eq_ignore_ascii_case("AlreadyRunning") => {
431+
Ok(ErrorCode::AlreadyRunning)
432+
}
433+
s if s.eq_ignore_ascii_case("CreateFailed") => {
434+
Ok(ErrorCode::CreateFailed)
435+
}
436+
_ => Err("unknown error code, expected one of: \
437+
'NoInstance', 'AlreadyInitialized', 'AlreadyRunning', \
438+
'CreateFailed'"),
439+
}
440+
}
441+
}

0 commit comments

Comments
 (0)