xref: /cloud-hypervisor/vmm/src/api/http/http_endpoint.rs (revision 99a98f270d8ac3acaff5a24d126e442350469bca)
1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 
6 use crate::api::http::{error_response, EndpointHandler, HttpError};
7 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
8 use crate::api::vm_coredump;
9 use crate::api::{
10     vm_add_device, vm_add_disk, vm_add_fs, vm_add_net, vm_add_pmem, vm_add_user_device,
11     vm_add_vdpa, vm_add_vsock, vm_boot, vm_counters, vm_create, vm_delete, vm_info, vm_pause,
12     vm_power_button, vm_reboot, vm_receive_migration, vm_remove_device, vm_resize, vm_resize_zone,
13     vm_restore, vm_resume, vm_send_migration, vm_shutdown, vm_snapshot, vmm_ping, vmm_shutdown,
14     ApiRequest, VmAction, VmConfig,
15 };
16 use crate::config::NetConfig;
17 use micro_http::{Body, Method, Request, Response, StatusCode, Version};
18 use std::fs::File;
19 use std::os::unix::io::IntoRawFd;
20 use std::sync::mpsc::Sender;
21 use std::sync::{Arc, Mutex};
22 use vmm_sys_util::eventfd::EventFd;
23 
24 // /api/v1/vm.create handler
25 pub struct VmCreate {}
26 
27 impl EndpointHandler for VmCreate {
28     fn handle_request(
29         &self,
30         req: &Request,
31         api_notifier: EventFd,
32         api_sender: Sender<ApiRequest>,
33     ) -> Response {
34         match req.method() {
35             Method::Put => {
36                 match &req.body {
37                     Some(body) => {
38                         // Deserialize into a VmConfig
39                         let mut vm_config: VmConfig = match serde_json::from_slice(body.raw())
40                             .map_err(HttpError::SerdeJsonDeserialize)
41                         {
42                             Ok(config) => config,
43                             Err(e) => return error_response(e, StatusCode::BadRequest),
44                         };
45 
46                         if let Some(ref mut nets) = vm_config.net {
47                             if nets.iter().any(|net| net.fds.is_some()) {
48                                 warn!("Ignoring FDs sent via the HTTP request body");
49                             }
50                             for net in nets {
51                                 net.fds = None;
52                             }
53                         }
54 
55                         // Call vm_create()
56                         match vm_create(api_notifier, api_sender, Arc::new(Mutex::new(vm_config)))
57                             .map_err(HttpError::ApiError)
58                         {
59                             Ok(_) => Response::new(Version::Http11, StatusCode::NoContent),
60                             Err(e) => error_response(e, StatusCode::InternalServerError),
61                         }
62                     }
63 
64                     None => Response::new(Version::Http11, StatusCode::BadRequest),
65                 }
66             }
67 
68             _ => error_response(HttpError::BadRequest, StatusCode::BadRequest),
69         }
70     }
71 }
72 
73 // Common handler for boot, shutdown and reboot
74 pub struct VmActionHandler {
75     action: VmAction,
76 }
77 
78 impl VmActionHandler {
79     pub fn new(action: VmAction) -> Self {
80         VmActionHandler { action }
81     }
82 }
83 
84 impl EndpointHandler for VmActionHandler {
85     fn put_handler(
86         &self,
87         api_notifier: EventFd,
88         api_sender: Sender<ApiRequest>,
89         body: &Option<Body>,
90         mut files: Vec<File>,
91     ) -> std::result::Result<Option<Body>, HttpError> {
92         use VmAction::*;
93         if let Some(body) = body {
94             match self.action {
95                 AddDevice(_) => vm_add_device(
96                     api_notifier,
97                     api_sender,
98                     Arc::new(serde_json::from_slice(body.raw())?),
99                 ),
100                 AddDisk(_) => vm_add_disk(
101                     api_notifier,
102                     api_sender,
103                     Arc::new(serde_json::from_slice(body.raw())?),
104                 ),
105                 AddFs(_) => vm_add_fs(
106                     api_notifier,
107                     api_sender,
108                     Arc::new(serde_json::from_slice(body.raw())?),
109                 ),
110                 AddPmem(_) => vm_add_pmem(
111                     api_notifier,
112                     api_sender,
113                     Arc::new(serde_json::from_slice(body.raw())?),
114                 ),
115                 AddNet(_) => {
116                     let mut net_cfg: NetConfig = serde_json::from_slice(body.raw())?;
117                     if net_cfg.fds.is_some() {
118                         warn!("Ignoring FDs sent via the HTTP request body");
119                         net_cfg.fds = None;
120                     }
121                     // Update network config with optional files that might have
122                     // been sent through control message.
123                     if !files.is_empty() {
124                         let fds = files.drain(..).map(|f| f.into_raw_fd()).collect();
125                         net_cfg.fds = Some(fds);
126                     }
127                     vm_add_net(api_notifier, api_sender, Arc::new(net_cfg))
128                 }
129                 AddVdpa(_) => vm_add_vdpa(
130                     api_notifier,
131                     api_sender,
132                     Arc::new(serde_json::from_slice(body.raw())?),
133                 ),
134                 AddVsock(_) => vm_add_vsock(
135                     api_notifier,
136                     api_sender,
137                     Arc::new(serde_json::from_slice(body.raw())?),
138                 ),
139                 AddUserDevice(_) => vm_add_user_device(
140                     api_notifier,
141                     api_sender,
142                     Arc::new(serde_json::from_slice(body.raw())?),
143                 ),
144                 RemoveDevice(_) => vm_remove_device(
145                     api_notifier,
146                     api_sender,
147                     Arc::new(serde_json::from_slice(body.raw())?),
148                 ),
149                 Resize(_) => vm_resize(
150                     api_notifier,
151                     api_sender,
152                     Arc::new(serde_json::from_slice(body.raw())?),
153                 ),
154                 ResizeZone(_) => vm_resize_zone(
155                     api_notifier,
156                     api_sender,
157                     Arc::new(serde_json::from_slice(body.raw())?),
158                 ),
159                 Restore(_) => vm_restore(
160                     api_notifier,
161                     api_sender,
162                     Arc::new(serde_json::from_slice(body.raw())?),
163                 ),
164                 Snapshot(_) => vm_snapshot(
165                     api_notifier,
166                     api_sender,
167                     Arc::new(serde_json::from_slice(body.raw())?),
168                 ),
169                 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
170                 Coredump(_) => vm_coredump(
171                     api_notifier,
172                     api_sender,
173                     Arc::new(serde_json::from_slice(body.raw())?),
174                 ),
175                 ReceiveMigration(_) => vm_receive_migration(
176                     api_notifier,
177                     api_sender,
178                     Arc::new(serde_json::from_slice(body.raw())?),
179                 ),
180                 SendMigration(_) => vm_send_migration(
181                     api_notifier,
182                     api_sender,
183                     Arc::new(serde_json::from_slice(body.raw())?),
184                 ),
185 
186                 _ => return Err(HttpError::BadRequest),
187             }
188         } else {
189             match self.action {
190                 Boot => vm_boot(api_notifier, api_sender),
191                 Delete => vm_delete(api_notifier, api_sender),
192                 Shutdown => vm_shutdown(api_notifier, api_sender),
193                 Reboot => vm_reboot(api_notifier, api_sender),
194                 Pause => vm_pause(api_notifier, api_sender),
195                 Resume => vm_resume(api_notifier, api_sender),
196                 PowerButton => vm_power_button(api_notifier, api_sender),
197                 _ => return Err(HttpError::BadRequest),
198             }
199         }
200         .map_err(HttpError::ApiError)
201     }
202 
203     fn get_handler(
204         &self,
205         api_notifier: EventFd,
206         api_sender: Sender<ApiRequest>,
207         _body: &Option<Body>,
208     ) -> std::result::Result<Option<Body>, HttpError> {
209         use VmAction::*;
210         match self.action {
211             Counters => vm_counters(api_notifier, api_sender).map_err(HttpError::ApiError),
212             _ => Err(HttpError::BadRequest),
213         }
214     }
215 }
216 
217 // /api/v1/vm.info handler
218 pub struct VmInfo {}
219 
220 impl EndpointHandler for VmInfo {
221     fn handle_request(
222         &self,
223         req: &Request,
224         api_notifier: EventFd,
225         api_sender: Sender<ApiRequest>,
226     ) -> Response {
227         match req.method() {
228             Method::Get => match vm_info(api_notifier, api_sender).map_err(HttpError::ApiError) {
229                 Ok(info) => {
230                     let mut response = Response::new(Version::Http11, StatusCode::OK);
231                     let info_serialized = serde_json::to_string(&info).unwrap();
232 
233                     response.set_body(Body::new(info_serialized));
234                     response
235                 }
236                 Err(e) => error_response(e, StatusCode::InternalServerError),
237             },
238             _ => error_response(HttpError::BadRequest, StatusCode::BadRequest),
239         }
240     }
241 }
242 
243 // /api/v1/vmm.info handler
244 pub struct VmmPing {}
245 
246 impl EndpointHandler for VmmPing {
247     fn handle_request(
248         &self,
249         req: &Request,
250         api_notifier: EventFd,
251         api_sender: Sender<ApiRequest>,
252     ) -> Response {
253         match req.method() {
254             Method::Get => match vmm_ping(api_notifier, api_sender).map_err(HttpError::ApiError) {
255                 Ok(pong) => {
256                     let mut response = Response::new(Version::Http11, StatusCode::OK);
257                     let info_serialized = serde_json::to_string(&pong).unwrap();
258 
259                     response.set_body(Body::new(info_serialized));
260                     response
261                 }
262                 Err(e) => error_response(e, StatusCode::InternalServerError),
263             },
264 
265             _ => error_response(HttpError::BadRequest, StatusCode::BadRequest),
266         }
267     }
268 }
269 
270 // /api/v1/vmm.shutdown handler
271 pub struct VmmShutdown {}
272 
273 impl EndpointHandler for VmmShutdown {
274     fn handle_request(
275         &self,
276         req: &Request,
277         api_notifier: EventFd,
278         api_sender: Sender<ApiRequest>,
279     ) -> Response {
280         match req.method() {
281             Method::Put => {
282                 match vmm_shutdown(api_notifier, api_sender).map_err(HttpError::ApiError) {
283                     Ok(_) => Response::new(Version::Http11, StatusCode::OK),
284                     Err(e) => error_response(e, StatusCode::InternalServerError),
285                 }
286             }
287             _ => error_response(HttpError::BadRequest, StatusCode::BadRequest),
288         }
289     }
290 }
291