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