diff --git a/vmm/src/api/http/mod.rs b/vmm/src/api/http/mod.rs index ad2062be6..839a49379 100644 --- a/vmm/src/api/http/mod.rs +++ b/vmm/src/api/http/mod.rs @@ -33,6 +33,7 @@ use crate::api::{ VmPause, VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeDisk, VmResizeZone, VmRestore, VmResume, VmSendMigration, VmShutdown, VmSnapshot, }; +use crate::config::ValidationError; use crate::device_manager::DeviceManagerError; use crate::landlock::Landlock; use crate::seccomp_filters::{Thread, get_seccomp_filter}; @@ -94,6 +95,12 @@ fn api_error_status_code(error: &ApiError) -> StatusCode { | VmError::NoDeviceToRemove(_) | VmError::DeviceManager(DeviceManagerError::UnknownDeviceId(_)), ) => StatusCode::NotFound, + Some(VmError::ConfigValidation(e)) => match e { + ValidationError::IdentifierNotUnique(_) | ValidationError::DuplicateDevicePath(_) => { + StatusCode::Conflict + } + _ => StatusCode::BadRequest, + }, _ => StatusCode::InternalServerError, } } @@ -532,6 +539,50 @@ mod tests { ); } + #[test] + fn test_duplicate_identifier_or_path_maps_to_conflict() { + assert_eq!( + api_error_status_code(&ApiError::VmAddDisk(VmError::ConfigValidation( + ValidationError::IdentifierNotUnique("disk0".to_string()) + ))), + StatusCode::Conflict + ); + assert_eq!( + api_error_status_code(&ApiError::VmAddVdpa(VmError::ConfigValidation( + ValidationError::IdentifierNotUnique("vdpa0".to_string()) + ))), + StatusCode::Conflict + ); + assert_eq!( + api_error_status_code(&ApiError::VmAddDevice(VmError::ConfigValidation( + ValidationError::DuplicateDevicePath("/dev/foo".to_string()) + ))), + StatusCode::Conflict + ); + assert_eq!( + api_error_status_code(&ApiError::VmRestore(VmError::ConfigValidation( + ValidationError::IdentifierNotUnique("net0".to_string()) + ))), + StatusCode::Conflict + ); + } + + #[test] + fn test_invalid_config_maps_to_bad_request() { + assert_eq!( + api_error_status_code(&ApiError::VmAddDisk(VmError::ConfigValidation( + ValidationError::InvalidIdentifier("__disk0".to_string()) + ))), + StatusCode::BadRequest + ); + assert_eq!( + api_error_status_code(&ApiError::VmAddDisk(VmError::ConfigValidation( + ValidationError::BalloonLargerThanRam(1024, 512) + ))), + StatusCode::BadRequest + ); + } + #[test] fn test_other_errors_map_to_internal_server_error() { assert_eq!( diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml index f7534a1f0..9f4307fe6 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml @@ -220,8 +220,12 @@ paths: $ref: "#/components/schemas/PciDeviceInfo" 204: description: The new device was successfully (cold) added to the VM instance. + 400: + description: The new device could not be added because the configuration is not valid. 404: description: The new device could not be added to the VM instance. + 409: + description: The new device could not be added because a device with the same identifier or path already exists. /vm.remove-device: put: @@ -258,8 +262,12 @@ paths: $ref: "#/components/schemas/PciDeviceInfo" 204: description: The new disk was successfully (cold) added to the VM instance. + 400: + description: The new disk could not be added because the configuration is not valid. 404: description: The new disk could not be added because the VM is not created. + 409: + description: The new disk could not be added because a device with the same identifier already exists. 500: description: The new disk could not be added to the VM instance. @@ -282,8 +290,12 @@ paths: $ref: "#/components/schemas/PciDeviceInfo" 204: description: The new device was successfully (cold) added to the VM instance. + 400: + description: The new device could not be added because the configuration is not valid. 404: description: The new device could not be added because the VM is not created. + 409: + description: The new device could not be added because a device with the same identifier already exists. 500: description: The new device could not be added to the VM instance. @@ -306,8 +318,12 @@ paths: $ref: "#/components/schemas/PciDeviceInfo" 204: description: The new device was successfully (cold) added to the VM instance. + 400: + description: The new device could not be added because the configuration is not valid. 404: description: The new device could not be added because the VM is not created. + 409: + description: The new device could not be added because a device with the same identifier already exists. 500: description: The new device could not be added to the VM instance. @@ -330,8 +346,12 @@ paths: $ref: "#/components/schemas/PciDeviceInfo" 204: description: The new device was successfully (cold) added to the VM instance. + 400: + description: The new device could not be added because the configuration is not valid. 404: description: The new device could not be added because the VM is not created. + 409: + description: The new device could not be added because a device with the same identifier already exists. 500: description: The new device could not be added to the VM instance. @@ -354,8 +374,12 @@ paths: $ref: "#/components/schemas/PciDeviceInfo" 204: description: The new device was successfully (cold) added to the VM instance. + 400: + description: The new device could not be added because the configuration is not valid. 404: description: The new device could not be added because the VM is not created. + 409: + description: The new device could not be added because a device with the same identifier already exists. 500: description: The new device could not be added to the VM instance. @@ -378,8 +402,12 @@ paths: $ref: "#/components/schemas/PciDeviceInfo" 204: description: The new device was successfully (cold) added to the VM instance. + 400: + description: The new device could not be added because the configuration is not valid. 404: description: The new device could not be added because the VM is not created. + 409: + description: The new device could not be added because a device with the same identifier already exists. 500: description: The new device could not be added to the VM instance. @@ -402,8 +430,12 @@ paths: $ref: "#/components/schemas/PciDeviceInfo" 204: description: The new vDPA device was successfully (cold) added to the VM instance. + 400: + description: The new vDPA device could not be added because the configuration is not valid. 404: description: The new vDPA device could not be added because the VM is not created. + 409: + description: The new vDPA device could not be added because a device with the same identifier already exists. 500: description: The new vDPA device could not be added to the VM instance. @@ -425,6 +457,10 @@ paths: description: The new device was successfully added to the VM instance. "204": description: The new device was successfully (cold) added to the VM instance. + "400": + description: The new device could not be added because the configuration is not valid. + "409": + description: The new device could not be added because a device with the same identifier already exists. "404": description: The new device could not be added to the VM instance. summary: Add a new userspace device to the VM @@ -485,8 +521,12 @@ paths: responses: 204: description: The VM instance was successfully restored. + 400: + description: The VM could not be restored because the restore configuration is not valid. 404: description: The VM instance could not be restored because it is already created. + 409: + description: The VM could not be restored because a device with the same identifier or path already exists. /vm.receive-migration: put: diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 64b86a56d..abd67e95b 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -338,7 +338,7 @@ pub enum ValidationError { #[error("Identifier {0} is not unique")] IdentifierNotUnique(String), /// Invalid identifier - #[error("Identifier {0} is not invalid")] + #[error("Identifier {0} is not valid")] InvalidIdentifier(String), /// Placing the device behind a virtual IOMMU is not supported #[error("Device does not support being placed behind IOMMU")]