xref: /cloud-hypervisor/vmm/src/api/http/http_endpoint.rs (revision d0225fe68fd14146bacc3be26f0b7e548ce9c239)
1c505cfaeSSamuel Ortiz // Copyright © 2019 Intel Corporation
24ca18c08SAlyssa Ross // Copyright 2024 Alyssa Ross <hi@alyssa.is>
3c505cfaeSSamuel Ortiz //
4c505cfaeSSamuel Ortiz // SPDX-License-Identifier: Apache-2.0
5c505cfaeSSamuel Ortiz //
6c505cfaeSSamuel Ortiz 
788a9f799SRob Bradford use std::fs::File;
888a9f799SRob Bradford use std::os::unix::io::IntoRawFd;
988a9f799SRob Bradford use std::sync::mpsc::Sender;
1088a9f799SRob Bradford 
1188a9f799SRob Bradford use micro_http::{Body, Method, Request, Response, StatusCode, Version};
1288a9f799SRob Bradford use vmm_sys_util::eventfd::EventFd;
1388a9f799SRob Bradford 
14c652625bSRob Bradford use crate::api::http::{error_response, EndpointHandler, HttpError};
15cefbf6b4SRob Bradford #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
164ca18c08SAlyssa Ross use crate::api::VmCoredump;
1743b36429SSamuel Ortiz use crate::api::{
18*d0225fe6SFabiano Fidêncio     AddDisk, ApiAction, ApiError, ApiRequest, NetConfig, VmAddDevice, VmAddFs, VmAddNet, VmAddPmem,
1933c15ca2SSongqian Li     VmAddUserDevice, VmAddVdpa, VmAddVsock, VmBoot, VmConfig, VmCounters, VmDelete, VmNmi, VmPause,
2033c15ca2SSongqian Li     VmPowerButton, VmReboot, VmReceiveMigration, VmRemoveDevice, VmResize, VmResizeZone, VmRestore,
2133c15ca2SSongqian Li     VmResume, VmSendMigration, VmShutdown, VmSnapshot,
2243b36429SSamuel Ortiz };
2333c15ca2SSongqian Li use crate::config::RestoreConfig;
24*d0225fe6SFabiano Fidêncio use crate::cpu::Error as CpuError;
25*d0225fe6SFabiano Fidêncio use crate::vm::Error as VmError;
26c505cfaeSSamuel Ortiz 
27c505cfaeSSamuel Ortiz // /api/v1/vm.create handler
28c505cfaeSSamuel Ortiz pub struct VmCreate {}
29c505cfaeSSamuel Ortiz 
30c505cfaeSSamuel Ortiz impl EndpointHandler for VmCreate {
handle_request( &self, req: &Request, api_notifier: EventFd, api_sender: Sender<ApiRequest>, ) -> Response31c505cfaeSSamuel Ortiz     fn handle_request(
32c505cfaeSSamuel Ortiz         &self,
33c505cfaeSSamuel Ortiz         req: &Request,
34c505cfaeSSamuel Ortiz         api_notifier: EventFd,
35c505cfaeSSamuel Ortiz         api_sender: Sender<ApiRequest>,
36c505cfaeSSamuel Ortiz     ) -> Response {
37c505cfaeSSamuel Ortiz         match req.method() {
38c505cfaeSSamuel Ortiz             Method::Put => {
39c505cfaeSSamuel Ortiz                 match &req.body {
40c505cfaeSSamuel Ortiz                     Some(body) => {
41c505cfaeSSamuel Ortiz                         // Deserialize into a VmConfig
42cc9899e0SSongqian Li                         let mut vm_config: Box<VmConfig> = match serde_json::from_slice(body.raw())
43c505cfaeSSamuel Ortiz                             .map_err(HttpError::SerdeJsonDeserialize)
44c505cfaeSSamuel Ortiz                         {
45c505cfaeSSamuel Ortiz                             Ok(config) => config,
46c505cfaeSSamuel Ortiz                             Err(e) => return error_response(e, StatusCode::BadRequest),
47c505cfaeSSamuel Ortiz                         };
48c505cfaeSSamuel Ortiz 
49fba0b5f9SAlyssa Ross                         if let Some(ref mut nets) = vm_config.net {
50fba0b5f9SAlyssa Ross                             if nets.iter().any(|net| net.fds.is_some()) {
51fba0b5f9SAlyssa Ross                                 warn!("Ignoring FDs sent via the HTTP request body");
52fba0b5f9SAlyssa Ross                             }
53fba0b5f9SAlyssa Ross                             for net in nets {
54fba0b5f9SAlyssa Ross                                 net.fds = None;
55fba0b5f9SAlyssa Ross                             }
56fba0b5f9SAlyssa Ross                         }
57fba0b5f9SAlyssa Ross 
584ca18c08SAlyssa Ross                         match crate::api::VmCreate
59cc9899e0SSongqian Li                             .send(api_notifier, api_sender, vm_config)
604ca066f0SRob Bradford                             .map_err(HttpError::ApiError)
61c505cfaeSSamuel Ortiz                         {
62f34ace76SSamuel Ortiz                             Ok(_) => Response::new(Version::Http11, StatusCode::NoContent),
63c505cfaeSSamuel Ortiz                             Err(e) => error_response(e, StatusCode::InternalServerError),
64c505cfaeSSamuel Ortiz                         }
65c505cfaeSSamuel Ortiz                     }
66c505cfaeSSamuel Ortiz 
67c505cfaeSSamuel Ortiz                     None => Response::new(Version::Http11, StatusCode::BadRequest),
68c505cfaeSSamuel Ortiz                 }
69c505cfaeSSamuel Ortiz             }
70c505cfaeSSamuel Ortiz 
71b0be5ff8SLiHui             _ => error_response(HttpError::BadRequest, StatusCode::BadRequest),
72c505cfaeSSamuel Ortiz         }
73c505cfaeSSamuel Ortiz     }
74c505cfaeSSamuel Ortiz }
75c505cfaeSSamuel Ortiz 
764ca18c08SAlyssa Ross pub trait GetHandler {
handle_request( &'static self, _api_notifier: EventFd, _api_sender: Sender<ApiRequest>, ) -> std::result::Result<Option<Body>, HttpError>774ca18c08SAlyssa Ross     fn handle_request(
784ca18c08SAlyssa Ross         &'static self,
794ca18c08SAlyssa Ross         _api_notifier: EventFd,
804ca18c08SAlyssa Ross         _api_sender: Sender<ApiRequest>,
814ca18c08SAlyssa Ross     ) -> std::result::Result<Option<Body>, HttpError> {
824ca18c08SAlyssa Ross         Err(HttpError::BadRequest)
834ca18c08SAlyssa Ross     }
844ca18c08SAlyssa Ross }
854ca18c08SAlyssa Ross 
864ca18c08SAlyssa Ross pub trait PutHandler {
handle_request( &'static self, _api_notifier: EventFd, _api_sender: Sender<ApiRequest>, _body: &Option<Body>, _files: Vec<File>, ) -> std::result::Result<Option<Body>, HttpError>874ca18c08SAlyssa Ross     fn handle_request(
884ca18c08SAlyssa Ross         &'static self,
894ca18c08SAlyssa Ross         _api_notifier: EventFd,
904ca18c08SAlyssa Ross         _api_sender: Sender<ApiRequest>,
914ca18c08SAlyssa Ross         _body: &Option<Body>,
924ca18c08SAlyssa Ross         _files: Vec<File>,
934ca18c08SAlyssa Ross     ) -> std::result::Result<Option<Body>, HttpError> {
944ca18c08SAlyssa Ross         Err(HttpError::BadRequest)
954ca18c08SAlyssa Ross     }
964ca18c08SAlyssa Ross }
974ca18c08SAlyssa Ross 
984ca18c08SAlyssa Ross pub trait HttpVmAction: GetHandler + PutHandler + Sync {}
994ca18c08SAlyssa Ross 
1004ca18c08SAlyssa Ross impl<T: GetHandler + PutHandler + Sync> HttpVmAction for T {}
1014ca18c08SAlyssa Ross 
1024ca18c08SAlyssa Ross macro_rules! vm_action_get_handler {
1034ca18c08SAlyssa Ross     ($action:ty) => {
1044ca18c08SAlyssa Ross         impl GetHandler for $action {
1054ca18c08SAlyssa Ross             fn handle_request(
1064ca18c08SAlyssa Ross                 &'static self,
1074ca18c08SAlyssa Ross                 api_notifier: EventFd,
1084ca18c08SAlyssa Ross                 api_sender: Sender<ApiRequest>,
1094ca18c08SAlyssa Ross             ) -> std::result::Result<Option<Body>, HttpError> {
1104ca18c08SAlyssa Ross                 self.send(api_notifier, api_sender, ())
1114ca18c08SAlyssa Ross                     .map_err(HttpError::ApiError)
1124ca18c08SAlyssa Ross             }
1134ca18c08SAlyssa Ross         }
1144ca18c08SAlyssa Ross 
1154ca18c08SAlyssa Ross         impl PutHandler for $action {}
1164ca18c08SAlyssa Ross     };
1174ca18c08SAlyssa Ross }
1184ca18c08SAlyssa Ross 
1194ca18c08SAlyssa Ross macro_rules! vm_action_put_handler {
1204ca18c08SAlyssa Ross     ($action:ty) => {
1214ca18c08SAlyssa Ross         impl PutHandler for $action {
1224ca18c08SAlyssa Ross             fn handle_request(
1234ca18c08SAlyssa Ross                 &'static self,
1244ca18c08SAlyssa Ross                 api_notifier: EventFd,
1254ca18c08SAlyssa Ross                 api_sender: Sender<ApiRequest>,
1264ca18c08SAlyssa Ross                 body: &Option<Body>,
1274ca18c08SAlyssa Ross                 _files: Vec<File>,
1284ca18c08SAlyssa Ross             ) -> std::result::Result<Option<Body>, HttpError> {
1294ca18c08SAlyssa Ross                 if body.is_some() {
1304ca18c08SAlyssa Ross                     Err(HttpError::BadRequest)
1314ca18c08SAlyssa Ross                 } else {
1324ca18c08SAlyssa Ross                     self.send(api_notifier, api_sender, ())
1334ca18c08SAlyssa Ross                         .map_err(HttpError::ApiError)
1344ca18c08SAlyssa Ross                 }
1354ca18c08SAlyssa Ross             }
1364ca18c08SAlyssa Ross         }
1374ca18c08SAlyssa Ross 
1384ca18c08SAlyssa Ross         impl GetHandler for $action {}
1394ca18c08SAlyssa Ross     };
1404ca18c08SAlyssa Ross }
1414ca18c08SAlyssa Ross 
1424ca18c08SAlyssa Ross macro_rules! vm_action_put_handler_body {
1434ca18c08SAlyssa Ross     ($action:ty) => {
1444ca18c08SAlyssa Ross         impl PutHandler for $action {
1454ca18c08SAlyssa Ross             fn handle_request(
1464ca18c08SAlyssa Ross                 &'static self,
1474ca18c08SAlyssa Ross                 api_notifier: EventFd,
1484ca18c08SAlyssa Ross                 api_sender: Sender<ApiRequest>,
1494ca18c08SAlyssa Ross                 body: &Option<Body>,
1504ca18c08SAlyssa Ross                 _files: Vec<File>,
1514ca18c08SAlyssa Ross             ) -> std::result::Result<Option<Body>, HttpError> {
1524ca18c08SAlyssa Ross                 if let Some(body) = body {
1534ca18c08SAlyssa Ross                     self.send(
1544ca18c08SAlyssa Ross                         api_notifier,
1554ca18c08SAlyssa Ross                         api_sender,
1564ca18c08SAlyssa Ross                         serde_json::from_slice(body.raw())?,
1574ca18c08SAlyssa Ross                     )
1584ca18c08SAlyssa Ross                     .map_err(HttpError::ApiError)
1594ca18c08SAlyssa Ross                 } else {
1604ca18c08SAlyssa Ross                     Err(HttpError::BadRequest)
1614ca18c08SAlyssa Ross                 }
1624ca18c08SAlyssa Ross             }
1634ca18c08SAlyssa Ross         }
1644ca18c08SAlyssa Ross 
1654ca18c08SAlyssa Ross         impl GetHandler for $action {}
1664ca18c08SAlyssa Ross     };
1674ca18c08SAlyssa Ross }
1684ca18c08SAlyssa Ross 
1694ca18c08SAlyssa Ross vm_action_get_handler!(VmCounters);
1704ca18c08SAlyssa Ross 
1714ca18c08SAlyssa Ross vm_action_put_handler!(VmBoot);
1724ca18c08SAlyssa Ross vm_action_put_handler!(VmDelete);
1734ca18c08SAlyssa Ross vm_action_put_handler!(VmShutdown);
1744ca18c08SAlyssa Ross vm_action_put_handler!(VmReboot);
1754ca18c08SAlyssa Ross vm_action_put_handler!(VmPause);
1764ca18c08SAlyssa Ross vm_action_put_handler!(VmResume);
1774ca18c08SAlyssa Ross vm_action_put_handler!(VmPowerButton);
178f40dd4a9SYi Wang vm_action_put_handler!(VmNmi);
1794ca18c08SAlyssa Ross 
1804ca18c08SAlyssa Ross vm_action_put_handler_body!(VmAddDevice);
1814ca18c08SAlyssa Ross vm_action_put_handler_body!(AddDisk);
1824ca18c08SAlyssa Ross vm_action_put_handler_body!(VmAddFs);
1834ca18c08SAlyssa Ross vm_action_put_handler_body!(VmAddPmem);
1844ca18c08SAlyssa Ross vm_action_put_handler_body!(VmAddVdpa);
1854ca18c08SAlyssa Ross vm_action_put_handler_body!(VmAddVsock);
1864ca18c08SAlyssa Ross vm_action_put_handler_body!(VmAddUserDevice);
1874ca18c08SAlyssa Ross vm_action_put_handler_body!(VmRemoveDevice);
1884ca18c08SAlyssa Ross vm_action_put_handler_body!(VmResizeZone);
1894ca18c08SAlyssa Ross vm_action_put_handler_body!(VmSnapshot);
1904ca18c08SAlyssa Ross vm_action_put_handler_body!(VmReceiveMigration);
1914ca18c08SAlyssa Ross vm_action_put_handler_body!(VmSendMigration);
1924ca18c08SAlyssa Ross 
1934ca18c08SAlyssa Ross #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
1944ca18c08SAlyssa Ross vm_action_put_handler_body!(VmCoredump);
1954ca18c08SAlyssa Ross 
1964ca18c08SAlyssa Ross impl PutHandler for VmAddNet {
handle_request( &'static self, api_notifier: EventFd, api_sender: Sender<ApiRequest>, body: &Option<Body>, mut files: Vec<File>, ) -> std::result::Result<Option<Body>, HttpError>1974ca18c08SAlyssa Ross     fn handle_request(
1984ca18c08SAlyssa Ross         &'static self,
1994ca18c08SAlyssa Ross         api_notifier: EventFd,
2004ca18c08SAlyssa Ross         api_sender: Sender<ApiRequest>,
2014ca18c08SAlyssa Ross         body: &Option<Body>,
2024ca18c08SAlyssa Ross         mut files: Vec<File>,
2034ca18c08SAlyssa Ross     ) -> std::result::Result<Option<Body>, HttpError> {
2044ca18c08SAlyssa Ross         if let Some(body) = body {
2054ca18c08SAlyssa Ross             let mut net_cfg: NetConfig = serde_json::from_slice(body.raw())?;
2064ca18c08SAlyssa Ross             if net_cfg.fds.is_some() {
2074ca18c08SAlyssa Ross                 warn!("Ignoring FDs sent via the HTTP request body");
2084ca18c08SAlyssa Ross                 net_cfg.fds = None;
2094ca18c08SAlyssa Ross             }
2104ca18c08SAlyssa Ross             if !files.is_empty() {
2114ca18c08SAlyssa Ross                 let fds = files.drain(..).map(|f| f.into_raw_fd()).collect();
2124ca18c08SAlyssa Ross                 net_cfg.fds = Some(fds);
2134ca18c08SAlyssa Ross             }
2144ca18c08SAlyssa Ross             self.send(api_notifier, api_sender, net_cfg)
2154ca18c08SAlyssa Ross                 .map_err(HttpError::ApiError)
2164ca18c08SAlyssa Ross         } else {
2174ca18c08SAlyssa Ross             Err(HttpError::BadRequest)
2184ca18c08SAlyssa Ross         }
2194ca18c08SAlyssa Ross     }
2204ca18c08SAlyssa Ross }
2214ca18c08SAlyssa Ross 
2224ca18c08SAlyssa Ross impl GetHandler for VmAddNet {}
2234ca18c08SAlyssa Ross 
224*d0225fe6SFabiano Fidêncio impl PutHandler for VmResize {
handle_request( &'static self, api_notifier: EventFd, api_sender: Sender<ApiRequest>, body: &Option<Body>, _files: Vec<File>, ) -> std::result::Result<Option<Body>, HttpError>225*d0225fe6SFabiano Fidêncio     fn handle_request(
226*d0225fe6SFabiano Fidêncio         &'static self,
227*d0225fe6SFabiano Fidêncio         api_notifier: EventFd,
228*d0225fe6SFabiano Fidêncio         api_sender: Sender<ApiRequest>,
229*d0225fe6SFabiano Fidêncio         body: &Option<Body>,
230*d0225fe6SFabiano Fidêncio         _files: Vec<File>,
231*d0225fe6SFabiano Fidêncio     ) -> std::result::Result<Option<Body>, HttpError> {
232*d0225fe6SFabiano Fidêncio         if let Some(body) = body {
233*d0225fe6SFabiano Fidêncio             self.send(
234*d0225fe6SFabiano Fidêncio                 api_notifier,
235*d0225fe6SFabiano Fidêncio                 api_sender,
236*d0225fe6SFabiano Fidêncio                 serde_json::from_slice(body.raw())?,
237*d0225fe6SFabiano Fidêncio             )
238*d0225fe6SFabiano Fidêncio             .map_err(|e| match e {
239*d0225fe6SFabiano Fidêncio                 ApiError::VmResize(VmError::CpuManager(CpuError::VcpuPendingRemovedVcpu)) => {
240*d0225fe6SFabiano Fidêncio                     HttpError::TooManyRequests
241*d0225fe6SFabiano Fidêncio                 }
242*d0225fe6SFabiano Fidêncio                 _ => HttpError::ApiError(e),
243*d0225fe6SFabiano Fidêncio             })
244*d0225fe6SFabiano Fidêncio         } else {
245*d0225fe6SFabiano Fidêncio             Err(HttpError::BadRequest)
246*d0225fe6SFabiano Fidêncio         }
247*d0225fe6SFabiano Fidêncio     }
248*d0225fe6SFabiano Fidêncio }
249*d0225fe6SFabiano Fidêncio 
250*d0225fe6SFabiano Fidêncio impl GetHandler for VmResize {}
251*d0225fe6SFabiano Fidêncio 
252b82f2557SPurna Pavan Chandra impl PutHandler for VmRestore {
handle_request( &'static self, api_notifier: EventFd, api_sender: Sender<ApiRequest>, body: &Option<Body>, mut files: Vec<File>, ) -> std::result::Result<Option<Body>, HttpError>253b82f2557SPurna Pavan Chandra     fn handle_request(
254b82f2557SPurna Pavan Chandra         &'static self,
255b82f2557SPurna Pavan Chandra         api_notifier: EventFd,
256b82f2557SPurna Pavan Chandra         api_sender: Sender<ApiRequest>,
257b82f2557SPurna Pavan Chandra         body: &Option<Body>,
258b82f2557SPurna Pavan Chandra         mut files: Vec<File>,
259b82f2557SPurna Pavan Chandra     ) -> std::result::Result<Option<Body>, HttpError> {
260b82f2557SPurna Pavan Chandra         if let Some(body) = body {
261b82f2557SPurna Pavan Chandra             let mut restore_cfg: RestoreConfig = serde_json::from_slice(body.raw())?;
262b82f2557SPurna Pavan Chandra 
263b82f2557SPurna Pavan Chandra             let mut fds = Vec::new();
264b82f2557SPurna Pavan Chandra             if !files.is_empty() {
265b82f2557SPurna Pavan Chandra                 fds = files.drain(..).map(|f| f.into_raw_fd()).collect();
266b82f2557SPurna Pavan Chandra             }
267b82f2557SPurna Pavan Chandra             let expected_fds = match restore_cfg.net_fds {
268b82f2557SPurna Pavan Chandra                 Some(ref net_fds) => net_fds.iter().map(|net| net.num_fds).sum(),
269b82f2557SPurna Pavan Chandra                 None => 0,
270b82f2557SPurna Pavan Chandra             };
271b82f2557SPurna Pavan Chandra             if fds.len() != expected_fds {
272b82f2557SPurna Pavan Chandra                 error!(
273b82f2557SPurna Pavan Chandra                     "Number of FDs expected: {}, but received: {}",
274b82f2557SPurna Pavan Chandra                     expected_fds,
275b82f2557SPurna Pavan Chandra                     fds.len()
276b82f2557SPurna Pavan Chandra                 );
277b82f2557SPurna Pavan Chandra                 return Err(HttpError::BadRequest);
278b82f2557SPurna Pavan Chandra             }
279b82f2557SPurna Pavan Chandra             if let Some(ref mut nets) = restore_cfg.net_fds {
280b82f2557SPurna Pavan Chandra                 warn!("Ignoring FDs sent via the HTTP request body");
281b82f2557SPurna Pavan Chandra                 let mut start_idx = 0;
282b82f2557SPurna Pavan Chandra                 for restored_net in nets.iter_mut() {
283b82f2557SPurna Pavan Chandra                     let end_idx = start_idx + restored_net.num_fds;
284b82f2557SPurna Pavan Chandra                     restored_net.fds = Some(fds[start_idx..end_idx].to_vec());
285b82f2557SPurna Pavan Chandra                     start_idx = end_idx;
286b82f2557SPurna Pavan Chandra                 }
287b82f2557SPurna Pavan Chandra             }
288b82f2557SPurna Pavan Chandra 
289b82f2557SPurna Pavan Chandra             self.send(api_notifier, api_sender, restore_cfg)
290b82f2557SPurna Pavan Chandra                 .map_err(HttpError::ApiError)
291b82f2557SPurna Pavan Chandra         } else {
292b82f2557SPurna Pavan Chandra             Err(HttpError::BadRequest)
293b82f2557SPurna Pavan Chandra         }
294b82f2557SPurna Pavan Chandra     }
295b82f2557SPurna Pavan Chandra }
296b82f2557SPurna Pavan Chandra 
297b82f2557SPurna Pavan Chandra impl GetHandler for VmRestore {}
298b82f2557SPurna Pavan Chandra 
299c505cfaeSSamuel Ortiz // Common handler for boot, shutdown and reboot
300c505cfaeSSamuel Ortiz pub struct VmActionHandler {
3014ca18c08SAlyssa Ross     action: &'static dyn HttpVmAction,
302c505cfaeSSamuel Ortiz }
303c505cfaeSSamuel Ortiz 
304c505cfaeSSamuel Ortiz impl VmActionHandler {
new(action: &'static dyn HttpVmAction) -> Self3054ca18c08SAlyssa Ross     pub fn new(action: &'static dyn HttpVmAction) -> Self {
3066ec605a7SRob Bradford         VmActionHandler { action }
307c505cfaeSSamuel Ortiz     }
308c505cfaeSSamuel Ortiz }
309c505cfaeSSamuel Ortiz 
310c505cfaeSSamuel Ortiz impl EndpointHandler for VmActionHandler {
put_handler( &self, api_notifier: EventFd, api_sender: Sender<ApiRequest>, body: &Option<Body>, files: Vec<File>, ) -> std::result::Result<Option<Body>, HttpError>3116aa29bdbSRob Bradford     fn put_handler(
312c505cfaeSSamuel Ortiz         &self,
313c505cfaeSSamuel Ortiz         api_notifier: EventFd,
314c505cfaeSSamuel Ortiz         api_sender: Sender<ApiRequest>,
3156aa29bdbSRob Bradford         body: &Option<Body>,
3164ca18c08SAlyssa Ross         files: Vec<File>,
31703818026SSebastien Boeuf     ) -> std::result::Result<Option<Body>, HttpError> {
3184ca18c08SAlyssa Ross         PutHandler::handle_request(self.action, api_notifier, api_sender, body, files)
319c505cfaeSSamuel Ortiz     }
320bca8a192SRob Bradford 
get_handler( &self, api_notifier: EventFd, api_sender: Sender<ApiRequest>, _body: &Option<Body>, ) -> std::result::Result<Option<Body>, HttpError>321bca8a192SRob Bradford     fn get_handler(
322bca8a192SRob Bradford         &self,
323bca8a192SRob Bradford         api_notifier: EventFd,
324bca8a192SRob Bradford         api_sender: Sender<ApiRequest>,
325bca8a192SRob Bradford         _body: &Option<Body>,
326bca8a192SRob Bradford     ) -> std::result::Result<Option<Body>, HttpError> {
3274ca18c08SAlyssa Ross         GetHandler::handle_request(self.action, api_notifier, api_sender)
328bca8a192SRob Bradford     }
329c505cfaeSSamuel Ortiz }
33042758244SSamuel Ortiz 
33142758244SSamuel Ortiz // /api/v1/vm.info handler
33242758244SSamuel Ortiz pub struct VmInfo {}
33342758244SSamuel Ortiz 
33442758244SSamuel Ortiz impl EndpointHandler for VmInfo {
handle_request( &self, req: &Request, api_notifier: EventFd, api_sender: Sender<ApiRequest>, ) -> Response33542758244SSamuel Ortiz     fn handle_request(
33642758244SSamuel Ortiz         &self,
33742758244SSamuel Ortiz         req: &Request,
33842758244SSamuel Ortiz         api_notifier: EventFd,
33942758244SSamuel Ortiz         api_sender: Sender<ApiRequest>,
34042758244SSamuel Ortiz     ) -> Response {
34142758244SSamuel Ortiz         match req.method() {
3424ca18c08SAlyssa Ross             Method::Get => match crate::api::VmInfo
3434ca18c08SAlyssa Ross                 .send(api_notifier, api_sender, ())
3444ca18c08SAlyssa Ross                 .map_err(HttpError::ApiError)
3454ca18c08SAlyssa Ross             {
34642758244SSamuel Ortiz                 Ok(info) => {
34742758244SSamuel Ortiz                     let mut response = Response::new(Version::Http11, StatusCode::OK);
34842758244SSamuel Ortiz                     let info_serialized = serde_json::to_string(&info).unwrap();
34942758244SSamuel Ortiz 
35042758244SSamuel Ortiz                     response.set_body(Body::new(info_serialized));
35142758244SSamuel Ortiz                     response
35242758244SSamuel Ortiz                 }
35342758244SSamuel Ortiz                 Err(e) => error_response(e, StatusCode::InternalServerError),
35442758244SSamuel Ortiz             },
355b0be5ff8SLiHui             _ => error_response(HttpError::BadRequest, StatusCode::BadRequest),
35642758244SSamuel Ortiz         }
35742758244SSamuel Ortiz     }
35842758244SSamuel Ortiz }
359a95fa1c4SSamuel Ortiz 
360a5186514SJose Carlos Venegas Munoz // /api/v1/vmm.info handler
361a5186514SJose Carlos Venegas Munoz pub struct VmmPing {}
362a5186514SJose Carlos Venegas Munoz 
363a5186514SJose Carlos Venegas Munoz impl EndpointHandler for VmmPing {
handle_request( &self, req: &Request, api_notifier: EventFd, api_sender: Sender<ApiRequest>, ) -> Response364a5186514SJose Carlos Venegas Munoz     fn handle_request(
365a5186514SJose Carlos Venegas Munoz         &self,
366a5186514SJose Carlos Venegas Munoz         req: &Request,
367a5186514SJose Carlos Venegas Munoz         api_notifier: EventFd,
368a5186514SJose Carlos Venegas Munoz         api_sender: Sender<ApiRequest>,
369a5186514SJose Carlos Venegas Munoz     ) -> Response {
370a5186514SJose Carlos Venegas Munoz         match req.method() {
3714ca18c08SAlyssa Ross             Method::Get => match crate::api::VmmPing
3724ca18c08SAlyssa Ross                 .send(api_notifier, api_sender, ())
3734ca18c08SAlyssa Ross                 .map_err(HttpError::ApiError)
3744ca18c08SAlyssa Ross             {
375a5186514SJose Carlos Venegas Munoz                 Ok(pong) => {
376a5186514SJose Carlos Venegas Munoz                     let mut response = Response::new(Version::Http11, StatusCode::OK);
377a5186514SJose Carlos Venegas Munoz                     let info_serialized = serde_json::to_string(&pong).unwrap();
378a5186514SJose Carlos Venegas Munoz 
379a5186514SJose Carlos Venegas Munoz                     response.set_body(Body::new(info_serialized));
380a5186514SJose Carlos Venegas Munoz                     response
381a5186514SJose Carlos Venegas Munoz                 }
382a5186514SJose Carlos Venegas Munoz                 Err(e) => error_response(e, StatusCode::InternalServerError),
383a5186514SJose Carlos Venegas Munoz             },
384b0be5ff8SLiHui 
385b0be5ff8SLiHui             _ => error_response(HttpError::BadRequest, StatusCode::BadRequest),
386a5186514SJose Carlos Venegas Munoz         }
387a5186514SJose Carlos Venegas Munoz     }
388a5186514SJose Carlos Venegas Munoz }
389a5186514SJose Carlos Venegas Munoz 
390a95fa1c4SSamuel Ortiz // /api/v1/vmm.shutdown handler
391a95fa1c4SSamuel Ortiz pub struct VmmShutdown {}
392a95fa1c4SSamuel Ortiz 
393a95fa1c4SSamuel Ortiz impl EndpointHandler for VmmShutdown {
handle_request( &self, req: &Request, api_notifier: EventFd, api_sender: Sender<ApiRequest>, ) -> Response394a95fa1c4SSamuel Ortiz     fn handle_request(
395a95fa1c4SSamuel Ortiz         &self,
396a95fa1c4SSamuel Ortiz         req: &Request,
397a95fa1c4SSamuel Ortiz         api_notifier: EventFd,
398a95fa1c4SSamuel Ortiz         api_sender: Sender<ApiRequest>,
399a95fa1c4SSamuel Ortiz     ) -> Response {
400a95fa1c4SSamuel Ortiz         match req.method() {
401a95fa1c4SSamuel Ortiz             Method::Put => {
4024ca18c08SAlyssa Ross                 match crate::api::VmmShutdown
4034ca18c08SAlyssa Ross                     .send(api_notifier, api_sender, ())
4044ca18c08SAlyssa Ross                     .map_err(HttpError::ApiError)
4054ca18c08SAlyssa Ross                 {
406a95fa1c4SSamuel Ortiz                     Ok(_) => Response::new(Version::Http11, StatusCode::OK),
407a95fa1c4SSamuel Ortiz                     Err(e) => error_response(e, StatusCode::InternalServerError),
408a95fa1c4SSamuel Ortiz                 }
409a95fa1c4SSamuel Ortiz             }
410b0be5ff8SLiHui             _ => error_response(HttpError::BadRequest, StatusCode::BadRequest),
411a95fa1c4SSamuel Ortiz         }
412a95fa1c4SSamuel Ortiz     }
413a95fa1c4SSamuel Ortiz }
414