Skip to content

Commit fca00f9

Browse files
committed
move error codes to an enum propolis-api-types
1 parent 5ad4809 commit fca00f9

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
@@ -436,19 +436,21 @@ async fn instance_ensure_common(
436436
{
437437
let existing_properties = existing.properties();
438438
if existing_properties.id != properties.id {
439-
return Err(HttpError::for_status(
440-
Some(format!(
439+
return Err(HttpError::for_client_error(
440+
Some(api::ErrorCode::AlreadyInitialized.to_string()),
441+
http::status::StatusCode::CONFLICT,
442+
format!(
441443
"Server already initialized with ID {}",
442444
existing_properties.id
443-
)),
444-
http::status::StatusCode::CONFLICT,
445+
),
445446
));
446447
}
447448

448449
if *existing_properties != properties {
449-
return Err(HttpError::for_status(
450-
Some("Cannot update running server".to_string()),
450+
return Err(HttpError::for_client_error(
451+
Some(api::ErrorCode::AlreadyRunning.to_string()),
451452
http::status::StatusCode::CONFLICT,
453+
"Cannot update running server".to_string(),
452454
));
453455
}
454456

@@ -512,10 +514,11 @@ async fn instance_ensure_common(
512514
vm_hdl.await.unwrap()
513515
}
514516
.map_err(|e| {
515-
HttpError::for_internal_error(format!(
516-
"failed to create instance: {}",
517-
e
518-
))
517+
HttpError::for_client_error(
518+
Some(api::ErrorCode::CreateFailed.to_string()),
519+
http::status::StatusCode::INTERNAL_SERVER_ERROR,
520+
format!("failed to create instance: {e}"),
521+
)
519522
})?;
520523

521524
if let Some(ramfb) = vm.framebuffer() {
@@ -737,7 +740,7 @@ async fn instance_state_monitor(
737740
// Inform the client of this condition so it doesn't wait forever.
738741
state_watcher.changed().await.map_err(|_| {
739742
HttpError::for_client_error(
740-
Some(NO_INSTANCE.to_string()),
743+
Some(api::ErrorCode::NoInstance.to_string()),
741744
http::status::StatusCode::GONE,
742745
format!(
743746
"No instance present; will never reach generation {}",
@@ -1052,11 +1055,9 @@ pub fn api() -> ApiDescription<Arc<DropshotEndpointContext>> {
10521055
api
10531056
}
10541057

1055-
const NO_INSTANCE: &str = "NO_INSTANCE";
1056-
10571058
fn not_created_error() -> HttpError {
10581059
HttpError::for_client_error(
1059-
Some(NO_INSTANCE.to_string()),
1060+
Some(api::ErrorCode::NoInstance.to_string()),
10601061
http::StatusCode::FAILED_DEPENDENCY,
10611062
"Server not initialized (no instance)".to_string(),
10621063
)

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};
@@ -380,3 +380,47 @@ pub struct SnapshotRequestPathParams {
380380
pub struct VCRRequestPathParams {
381381
pub id: Uuid,
382382
}
383+
384+
/// Error codes used to populate the `error_code` field of Dropshot API responses.
385+
#[derive(
386+
Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema,
387+
)]
388+
pub enum ErrorCode {
389+
/// This `propolis-server` process has not received an `InstanceEnsure`
390+
/// request yet.
391+
NoInstance,
392+
/// This `propolis-server` process has already received an `InstanceEnsure`
393+
/// request with a different ID.
394+
AlreadyInitialized,
395+
/// Cannot update a running server.
396+
AlreadyRunning,
397+
/// Instance creation failed
398+
CreateFailed,
399+
}
400+
401+
impl fmt::Display for ErrorCode {
402+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
403+
fmt::Debug::fmt(self, f)
404+
}
405+
}
406+
407+
impl std::str::FromStr for ErrorCode {
408+
type Err = &'static str;
409+
fn from_str(s: &str) -> Result<Self, Self::Err> {
410+
match s.trim() {
411+
s if s.eq_ignore_ascii_case("NoInstance") => Ok(Self::NoInstance),
412+
s if s.eq_ignore_ascii_case("AlreadyInitialized") => {
413+
Ok(ErrorCode::AlreadyInitialized)
414+
}
415+
s if s.eq_ignore_ascii_case("AlreadyRunning") => {
416+
Ok(ErrorCode::AlreadyRunning)
417+
}
418+
s if s.eq_ignore_ascii_case("CreateFailed") => {
419+
Ok(ErrorCode::CreateFailed)
420+
}
421+
_ => Err("unknown error code, expected one of: \
422+
'NoInstance', 'AlreadyInitialized', 'AlreadyRunning', \
423+
'CreateFailed'"),
424+
}
425+
}
426+
}

0 commit comments

Comments
 (0)