Skip to content

Commit 0565c3e

Browse files
vmm & api_server refactoring
The api_server now depends on the vmm and imports all the necessary structures from it. The structures are defined in the vmm_config crate. Redefined the one shot channels by which the vmm and the API communicate so that on each channel we put bits of information that are in a vmm specific language. As much as possible, renamed the structures in the VMM so they do not have words related to the API in them. Refactored the error handling. We now have 2 types of errors: * errors associated with the VMM public interface (VmmActionError). Each of the sub-categories of this error kind corresponds to an action from the public interface as defined in the enum VmmAction. * errors associated with the internal state of the VMM or its components. These errors cannot be directly triggered by the user. Signed-off-by: Andreea Florescu <[email protected]>
1 parent b23a56e commit 0565c3e

File tree

24 files changed

+919
-1002
lines changed

24 files changed

+919
-1002
lines changed

api_server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ jailer = { path = "../jailer" }
2020
logger = { path = "../logger" }
2121
net_util = { path = "../net_util" }
2222
sys_util = { path = "../sys_util" }
23+
vmm = { path = "../vmm" }

api_server/src/http_service.rs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@ use hyper::{self, Chunk, Headers, Method, StatusCode};
1111
use serde_json;
1212

1313
use data_model::mmds::Mmds;
14-
use data_model::vm::{BlockDeviceConfig, MachineConfiguration};
14+
use data_model::vm::{BlockDeviceConfig, VmConfig};
1515
use logger::{Metric, METRICS};
1616
use request::actions::ActionBody;
17-
use request::boot_source::BootSourceConfig;
1817
use request::drive::PatchDrivePayload;
19-
use request::instance_info::InstanceInfo;
20-
use request::logger::APILoggerDescription;
21-
use request::net::NetworkInterfaceBody;
22-
use request::{IntoParsedRequest, ParsedRequest, VmmAction};
18+
use request::{GenerateHyperResponse, IntoParsedRequest, ParsedRequest};
2319
use sys_util::EventFd;
20+
use vmm::vmm_config::boot_source::BootSourceConfig;
21+
use vmm::vmm_config::instance_info::InstanceInfo;
22+
use vmm::vmm_config::logger::LoggerConfig;
23+
use vmm::vmm_config::net::NetworkInterfaceBody;
24+
use vmm::VmmAction;
2425

2526
fn build_response_base<B: Into<hyper::Body>>(
2627
status: StatusCode,
@@ -256,7 +257,7 @@ fn parse_logger_req<'a>(
256257

257258
0 if method == Method::Put => {
258259
METRICS.put_api_requests.logger_count.inc();
259-
Ok(serde_json::from_slice::<APILoggerDescription>(body)
260+
Ok(serde_json::from_slice::<LoggerConfig>(body)
260261
.map_err(|e| {
261262
METRICS.put_api_requests.logger_fails.inc();
262263
Error::SerdeJson(e)
@@ -280,7 +281,7 @@ fn parse_machine_config_req<'a>(
280281
match path_tokens[1..].len() {
281282
0 if method == Method::Get => {
282283
METRICS.get_api_requests.machine_cfg_count.inc();
283-
let empty_machine_config = MachineConfiguration {
284+
let empty_machine_config = VmConfig {
284285
vcpu_count: None,
285286
mem_size_mib: None,
286287
ht_enabled: None,
@@ -296,7 +297,7 @@ fn parse_machine_config_req<'a>(
296297

297298
0 if method == Method::Put => {
298299
METRICS.put_api_requests.machine_cfg_count.inc();
299-
Ok(serde_json::from_slice::<MachineConfiguration>(body)
300+
Ok(serde_json::from_slice::<VmConfig>(body)
300301
.map_err(|e| {
301302
METRICS.put_api_requests.machine_cfg_fails.inc();
302303
Error::SerdeJson(e)
@@ -580,12 +581,13 @@ mod tests {
580581
use serde_json::{Map, Value};
581582
use std::path::PathBuf;
582583

583-
use data_model::vm::{CpuFeaturesTemplate, DeviceState};
584+
use data_model::vm::CpuFeaturesTemplate;
584585
use futures::sync::oneshot;
585586
use hyper::header::{ContentType, Headers};
586587
use hyper::Body;
587588
use net_util::MacAddr;
588-
use request::VmmAction;
589+
use vmm::vmm_config::DeviceState;
590+
use vmm::VmmAction;
589591

590592
fn body_to_string(body: hyper::Body) -> String {
591593
let ret = body
@@ -1006,7 +1008,7 @@ mod tests {
10061008

10071009
// PUT
10081010
let logger_body =
1009-
serde_json::from_slice::<APILoggerDescription>(&body).expect("deserialization failed");
1011+
serde_json::from_slice::<LoggerConfig>(&body).expect("deserialization failed");
10101012
match parse_logger_req(&path_tokens, &path, Method::Put, &body) {
10111013
Ok(pr) => {
10121014
let (sender, receiver) = oneshot::channel();
@@ -1056,18 +1058,20 @@ mod tests {
10561058
);
10571059

10581060
// PUT
1059-
let mcb = MachineConfiguration {
1061+
let vm_config = VmConfig {
10601062
vcpu_count: Some(42),
10611063
mem_size_mib: Some(1025),
10621064
ht_enabled: Some(true),
10631065
cpu_template: Some(CpuFeaturesTemplate::T2),
10641066
};
10651067

1066-
match mcb.into_parsed_request(None, Method::Put) {
1067-
Ok(pr) => match parse_machine_config_req(&path_tokens, &path, Method::Put, &body) {
1068-
Ok(pr_mcb) => assert!(pr.eq(&pr_mcb)),
1069-
_ => assert!(false),
1070-
},
1068+
match vm_config.into_parsed_request(None, Method::Put) {
1069+
Ok(parsed_req) => {
1070+
match parse_machine_config_req(&path_tokens, &path, Method::Put, &body) {
1071+
Ok(other_parsed_req) => assert!(parsed_req.eq(&other_parsed_req)),
1072+
_ => assert!(false),
1073+
}
1074+
}
10711075
_ => assert!(false),
10721076
}
10731077

api_server/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ extern crate tokio_uds;
1111
extern crate data_model;
1212
extern crate fc_util;
1313
extern crate jailer;
14+
extern crate vmm;
1415
#[macro_use]
1516
extern crate logger;
1617
extern crate net_util;
@@ -34,9 +35,9 @@ use tokio_uds::UnixListener;
3435
use data_model::mmds::Mmds;
3536
use http_service::ApiServerHttpService;
3637
use logger::{Metric, METRICS};
37-
use request::instance_info::InstanceInfo;
38-
use request::VmmAction;
3938
use sys_util::EventFd;
39+
use vmm::vmm_config::instance_info::InstanceInfo;
40+
use vmm::VmmAction;
4041

4142
#[derive(Debug)]
4243
pub enum Error {

api_server/src/request/actions.rs

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use futures::sync::oneshot;
66
use hyper::Method;
77
use serde_json::Value;
88

9-
use request::{IntoParsedRequest, ParsedRequest, VmmAction};
9+
use request::{IntoParsedRequest, ParsedRequest};
10+
use vmm::VmmAction;
1011

1112
// The names of the members from this enum must precisely correspond (as a string) to the possible
1213
// values of "action_type" from the json request body. This is useful to get a strongly typed
@@ -22,23 +23,13 @@ pub enum DeviceType {
2223
Drive,
2324
}
2425

25-
// Represents the associated json block from the sync request body.
26-
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
27-
#[serde(deny_unknown_fields)]
28-
pub struct InstanceDeviceDetachAction {
29-
pub device_type: DeviceType,
30-
pub device_resource_id: String,
31-
pub force: bool,
32-
}
33-
3426
// The model of the json body from a sync request. We use Serde to transform each associated
3527
// json body into this.
3628
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
3729
#[serde(deny_unknown_fields)]
3830
pub struct ActionBody {
3931
pub action_type: ActionType,
4032
#[serde(skip_serializing_if = "Option::is_none")]
41-
pub instance_device_detach_action: Option<InstanceDeviceDetachAction>,
4233
pub payload: Option<Value>,
4334
}
4435

@@ -107,36 +98,31 @@ mod tests {
10798
// Test InstanceStart.
10899
let action_body = ActionBody {
109100
action_type: ActionType::InstanceStart,
110-
instance_device_detach_action: None,
111101
payload: None,
112102
};
113103
assert!(validate_payload(&action_body).is_ok());
114104
// Error case: InstanceStart with payload.
115105
let action_body = ActionBody {
116106
action_type: ActionType::InstanceStart,
117-
instance_device_detach_action: None,
118107
payload: Some(Value::String("dummy-payload".to_string())),
119108
};
120109
assert!(validate_payload(&action_body).is_err());
121110

122111
// Test BlockDeviceRescan
123112
let action_body = ActionBody {
124113
action_type: ActionType::BlockDeviceRescan,
125-
instance_device_detach_action: None,
126114
payload: Some(Value::String(String::from("dummy_id"))),
127115
};
128116
assert!(validate_payload(&action_body).is_ok());
129117
// Error case: no payload.
130118
let action_body = ActionBody {
131119
action_type: ActionType::BlockDeviceRescan,
132-
instance_device_detach_action: None,
133120
payload: None,
134121
};
135122
assert!(validate_payload(&action_body).is_err());
136123
// Error case: payload is not String.
137124
let action_body = ActionBody {
138125
action_type: ActionType::BlockDeviceRescan,
139-
instance_device_detach_action: None,
140126
payload: Some(Value::Bool(false)),
141127
};
142128
assert!(validate_payload(&action_body).is_err());
@@ -167,13 +153,10 @@ mod tests {
167153
}
168154

169155
{
170-
let json = "{
171-
\"action_type\": \"InstanceStart\",
172-
\"instance_device_detach_action\": {\
173-
\"device_type\": \"Drive\",
174-
\"device_resource_id\": \"dummy\",
175-
\"force\": true}
176-
}";
156+
let json = r#"{
157+
"action_type": "InstanceStart"
158+
}"#;
159+
177160
let (sender, receiver) = oneshot::channel();
178161
let req: ParsedRequest = ParsedRequest::Sync(VmmAction::StartMicroVm(sender), receiver);
179162
let result: Result<ActionBody, serde_json::Error> = serde_json::from_str(json);

api_server/src/request/boot_source.rs

Lines changed: 4 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,11 @@
11
use std::result;
22

33
use futures::sync::oneshot;
4-
use hyper::{Method, Response, StatusCode};
4+
use hyper::Method;
55

6-
use http_service::{json_fault_message, json_response};
7-
use request::{GenerateResponse, IntoParsedRequest, ParsedRequest, VmmAction};
8-
9-
#[derive(Debug, Deserialize, PartialEq, Serialize)]
10-
#[serde(deny_unknown_fields)]
11-
pub struct BootSourceConfig {
12-
pub kernel_image_path: String,
13-
#[serde(skip_serializing_if = "Option::is_none")]
14-
pub boot_args: Option<String>,
15-
}
16-
17-
#[derive(Debug)]
18-
pub enum BootSourceConfigError {
19-
InvalidKernelPath,
20-
InvalidKernelCommandLine,
21-
UpdateNotAllowedPostBoot,
22-
}
23-
24-
impl GenerateResponse for BootSourceConfigError {
25-
fn generate_response(&self) -> Response {
26-
use self::BootSourceConfigError::*;
27-
match *self {
28-
InvalidKernelPath => json_response(
29-
StatusCode::BadRequest,
30-
json_fault_message(
31-
"The kernel file cannot \
32-
be opened due to invalid kernel path or invalid permissions.",
33-
),
34-
),
35-
InvalidKernelCommandLine => json_response(
36-
StatusCode::BadRequest,
37-
json_fault_message("The kernel command line is invalid!"),
38-
),
39-
UpdateNotAllowedPostBoot => json_response(
40-
StatusCode::BadRequest,
41-
json_fault_message("The update operation is not allowed after boot."),
42-
),
43-
}
44-
}
45-
}
6+
use request::{IntoParsedRequest, ParsedRequest};
7+
use vmm::vmm_config::boot_source::BootSourceConfig;
8+
use vmm::VmmAction;
469

4710
impl IntoParsedRequest for BootSourceConfig {
4811
fn into_parsed_request(
@@ -62,22 +25,6 @@ impl IntoParsedRequest for BootSourceConfig {
6225
mod tests {
6326
use super::*;
6427

65-
#[test]
66-
fn test_generate_response_put_boot_source_config_error() {
67-
assert_eq!(
68-
BootSourceConfigError::InvalidKernelPath
69-
.generate_response()
70-
.status(),
71-
StatusCode::BadRequest
72-
);
73-
assert_eq!(
74-
BootSourceConfigError::InvalidKernelCommandLine
75-
.generate_response()
76-
.status(),
77-
StatusCode::BadRequest
78-
);
79-
}
80-
8128
#[test]
8229
fn test_into_parsed_request() {
8330
let body = BootSourceConfig {

0 commit comments

Comments
 (0)