diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index d15cffe29..7e1a68717 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -5,7 +5,7 @@ use crate::api::http_endpoint::{ VmActionHandler, VmAddDevice, VmAddDisk, VmAddNet, VmAddPmem, VmCreate, VmInfo, VmRemoveDevice, - VmResize, VmSnapshot, VmmPing, VmmShutdown, + VmResize, VmRestore, VmSnapshot, VmmPing, VmmShutdown, }; use crate::api::{ApiRequest, VmAction}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; @@ -63,6 +63,7 @@ lazy_static! { r.routes.insert(endpoint!("/vm.shutdown"), Box::new(VmActionHandler::new(VmAction::Shutdown))); r.routes.insert(endpoint!("/vm.reboot"), Box::new(VmActionHandler::new(VmAction::Reboot))); r.routes.insert(endpoint!("/vm.snapshot"), Box::new(VmSnapshot {})); + r.routes.insert(endpoint!("/vm.restore"), Box::new(VmRestore {})); r.routes.insert(endpoint!("/vmm.shutdown"), Box::new(VmmShutdown {})); r.routes.insert(endpoint!("/vmm.ping"), Box::new(VmmPing {})); r.routes.insert(endpoint!("/vm.resize"), Box::new(VmResize {})); diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs index 1a21b09ef..0884c82f5 100644 --- a/vmm/src/api/http_endpoint.rs +++ b/vmm/src/api/http_endpoint.rs @@ -6,9 +6,10 @@ use crate::api::http::EndpointHandler; use crate::api::{ vm_add_device, vm_add_disk, vm_add_net, vm_add_pmem, vm_boot, vm_create, vm_delete, vm_info, - vm_pause, vm_reboot, vm_remove_device, vm_resize, vm_resume, vm_shutdown, vm_snapshot, - vmm_ping, vmm_shutdown, ApiError, ApiRequest, ApiResult, DeviceConfig, DiskConfig, NetConfig, - PmemConfig, VmAction, VmConfig, VmRemoveDeviceData, VmResizeData, VmSnapshotConfig, + vm_pause, vm_reboot, vm_remove_device, vm_resize, vm_restore, vm_resume, vm_shutdown, + vm_snapshot, vmm_ping, vmm_shutdown, ApiError, ApiRequest, ApiResult, DeviceConfig, DiskConfig, + NetConfig, PmemConfig, VmAction, VmConfig, VmRemoveDeviceData, VmResizeData, VmRestoreConfig, + VmSnapshotConfig, }; use micro_http::{Body, Method, Request, Response, StatusCode, Version}; use serde_json::Error as SerdeError; @@ -46,6 +47,9 @@ pub enum HttpError { /// Could not snapshot a VM VmSnapshot(ApiError), + /// Could not restore a VM + VmRestore(ApiError), + /// Could not act on a VM VmAction(ApiError), @@ -234,6 +238,45 @@ impl EndpointHandler for VmSnapshot { } } +// /api/v1/vm.restore handler +pub struct VmRestore {} + +impl EndpointHandler for VmRestore { + fn handle_request( + &self, + req: &Request, + api_notifier: EventFd, + api_sender: Sender, + ) -> Response { + match req.method() { + Method::Put => { + match &req.body { + Some(body) => { + // Deserialize into a VmRestoreConfig + let vm_restore_data: VmRestoreConfig = + match serde_json::from_slice(body.raw()) + .map_err(HttpError::SerdeJsonDeserialize) + { + Ok(data) => data, + Err(e) => return error_response(e, StatusCode::BadRequest), + }; + + // Call vm_restore() + match vm_restore(api_notifier, api_sender, Arc::new(vm_restore_data)) + .map_err(HttpError::VmRestore) + { + Ok(_) => Response::new(Version::Http11, StatusCode::NoContent), + Err(e) => error_response(e, StatusCode::InternalServerError), + } + } + None => Response::new(Version::Http11, StatusCode::BadRequest), + } + } + _ => Response::new(Version::Http11, StatusCode::BadRequest), + } + } +} + // /api/v1/vmm.info handler pub struct VmmPing {} diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml index 62cf8560f..4d166f5cd 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml @@ -171,24 +171,6 @@ paths: 404: description: The device could not be removed from the VM instance. - /vm.snapshot: - put: - summary: Returns a VM snapshot. - requestBody: - description: The snapshot configuration - content: - application/json: - schema: - $ref: '#/components/schemas/VmSnapshotConfig' - required: true - responses: - 204: - description: The VM instance was successfully snapshotted. - 404: - description: The VM instance could not be snapshotted because it is not created. - 405: - description: The VM instance could not be snapshotted because it is not booted. - /vm.add-disk: put: summary: Add a new disk to the VM @@ -237,6 +219,40 @@ paths: 500: description: The new device could not be added to the VM instance. + /vm.snapshot: + put: + summary: Returns a VM snapshot. + requestBody: + description: The snapshot configuration + content: + application/json: + schema: + $ref: '#/components/schemas/VmSnapshotConfig' + required: true + responses: + 204: + description: The VM instance was successfully snapshotted. + 404: + description: The VM instance could not be snapshotted because it is not created. + 405: + description: The VM instance could not be snapshotted because it is not booted. + + /vm.restore: + put: + summary: Restore a VM from a snapshot. + requestBody: + description: The restore configuration + content: + application/json: + schema: + $ref: '#/components/schemas/VmRestoreConfig' + required: true + responses: + 204: + description: The VM instance was successfully restored. + 404: + description: The VM instance could not be restored because it is already created. + components: schemas: @@ -566,3 +582,9 @@ components: properties: destination_url: type: string + + VmRestoreConfig: + type: object + properties: + source_url: + type: string