diff --git a/bin/propolis-server/src/lib/server.rs b/bin/propolis-server/src/lib/server.rs index ae44f8248..48b889f44 100644 --- a/bin/propolis-server/src/lib/server.rs +++ b/bin/propolis-server/src/lib/server.rs @@ -343,14 +343,7 @@ async fn instance_get_common( rqctx: &RequestContext>, ) -> Result { let ctx = rqctx.context(); - ctx.vm.get().await.map_err(|e| match e { - VmError::NotCreated | VmError::WaitingToInitialize => { - not_created_error() - } - _ => HttpError::for_internal_error(format!( - "unexpected error from VM controller: {e}" - )), - }) + ctx.vm.get().await.ok_or_else(not_created_error) } #[endpoint { @@ -393,14 +386,7 @@ async fn instance_state_monitor( let ctx = rqctx.context(); let gen = request.into_inner().gen; let mut state_watcher = - ctx.vm.state_watcher().await.map_err(|e| match e { - VmError::NotCreated | VmError::WaitingToInitialize => { - not_created_error() - } - _ => HttpError::for_internal_error(format!( - "unexpected error from VM controller: {e}" - )), - })?; + ctx.vm.state_watcher().await.ok_or_else(not_created_error)?; loop { let last = state_watcher.borrow().clone(); @@ -440,9 +426,7 @@ async fn instance_state_put( .put_state(requested_state) .map(|_| HttpResponseUpdatedNoContent {}) .map_err(|e| match e { - VmError::NotCreated | VmError::WaitingToInitialize => { - not_created_error() - } + VmError::WaitingToInitialize => not_created_error(), VmError::ForbiddenStateChange(reason) => HttpError::for_status( Some(format!("instance state change not allowed: {}", reason)), hyper::StatusCode::FORBIDDEN, @@ -614,14 +598,7 @@ async fn instance_migrate_status( .state_watcher() .await .map(|rx| HttpResponseOk(rx.borrow().migration.clone())) - .map_err(|e| match e { - VmError::NotCreated | VmError::WaitingToInitialize => { - not_created_error() - } - _ => HttpError::for_internal_error(format!( - "unexpected error from VM controller: {e}" - )), - }) + .ok_or_else(not_created_error) } /// Issues a snapshot request to a crucible backend. diff --git a/bin/propolis-server/src/lib/vm/mod.rs b/bin/propolis-server/src/lib/vm/mod.rs index 87364fa36..fea20119f 100644 --- a/bin/propolis-server/src/lib/vm/mod.rs +++ b/bin/propolis-server/src/lib/vm/mod.rs @@ -165,9 +165,6 @@ pub(crate) enum VmError { #[error("VM operation result channel unexpectedly closed")] ResultChannelClosed, - #[error("VM not created")] - NotCreated, - #[error("VM is currently initializing")] WaitingToInitialize, @@ -317,18 +314,23 @@ impl Vm { /// Returns the state, properties, and instance spec for the instance most /// recently wrapped by this `Vm`. - pub(super) async fn get(&self) -> Result { + /// + /// # Returns + /// + /// - `Some` if the VM has been created. + /// - `None` if no VM has ever been created. + pub(super) async fn get(&self) -> Option { let guard = self.inner.read().await; match &guard.state { // If no VM has ever been created, there's nothing to get. - VmState::NoVm => Err(VmError::NotCreated), + VmState::NoVm => None, // If the VM is active, pull the required data out of its objects. VmState::Active(vm) => { let spec = vm.objects().lock_shared().await.instance_spec().clone(); let state = vm.external_state_rx.borrow().clone(); - Ok(InstanceSpecGetResponse { + Some(InstanceSpecGetResponse { properties: vm.properties.clone(), spec: VersionedInstanceSpec::V0(spec.into()), state: state.state, @@ -340,7 +342,7 @@ impl Vm { // machine. VmState::WaitingForInit(vm) | VmState::Rundown(vm) - | VmState::RundownComplete(vm) => Ok(InstanceSpecGetResponse { + | VmState::RundownComplete(vm) => Some(InstanceSpecGetResponse { properties: vm.properties.clone(), state: vm.external_state_rx.borrow().state, spec: VersionedInstanceSpec::V0(vm.spec.clone().into()), @@ -350,16 +352,21 @@ impl Vm { /// Yields a handle to the most recent instance state receiver wrapped by /// this `Vm`. - pub(super) async fn state_watcher( - &self, - ) -> Result { + /// + /// # Returns + /// + /// - `Some` if the VM has been created. + /// - `None` if no VM has ever been created. + pub(super) async fn state_watcher(&self) -> Option { let guard = self.inner.read().await; match &guard.state { - VmState::NoVm => Err(VmError::NotCreated), - VmState::Active(vm) => Ok(vm.external_state_rx.clone()), + VmState::NoVm => None, + VmState::Active(vm) => Some(vm.external_state_rx.clone()), VmState::WaitingForInit(vm) | VmState::Rundown(vm) - | VmState::RundownComplete(vm) => Ok(vm.external_state_rx.clone()), + | VmState::RundownComplete(vm) => { + Some(vm.external_state_rx.clone()) + } } }