Skip to content

Commit

Permalink
Add some logging and tests to vCPU hotplugging
Browse files Browse the repository at this point in the history
New metrics added to logger regarding number of hotplug requests and
number of hotplug fails. Simple tests for API added.

Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
  • Loading branch information
JamesC1305 committed Jun 11, 2024
1 parent 1989704 commit d2d6d41
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 11 deletions.
60 changes: 51 additions & 9 deletions src/firecracker/src/api_server/request/hotplug.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use vmm::logger::{IncMetric, METRICS};

use vmm::rpc_interface::VmmAction;
use vmm::vmm_config::hotplug::VcpuHotPlugConfig;
use vmm::vmm_config::machine_config::MachineConfigUpdate;

use super::{Body, StatusCode, Method};
use super::super::parsed_request::{ParsedRequest, RequestError};

pub(crate) fn parse_put_hotplug(body: &Body, resource_type_from_path: Option<&str>) -> Result<ParsedRequest, RequestError> {
METRICS.put_api_requests.hotplug.inc();
match resource_type_from_path {
// TODO: Implement memory hotplug
Some(resource) => match resource {
"vcpu" => parse_put_vcpu_hotplug(body),
_ => Err(RequestError::InvalidPathMethod(
format!("/hotplug/{}", request_type),
format!("/hotplug/{}", resource),
Method::Put,
)),
},
Expand All @@ -27,18 +27,60 @@ pub(crate) fn parse_put_hotplug(body: &Body, resource_type_from_path: Option<&st


fn parse_put_vcpu_hotplug(body: &Body) -> Result<ParsedRequest, RequestError> {

let config = serde_json::from_slice::<vCPUHotPlugConfig>(body.raw()).map_err(|err| {
// TODO: Error metrics
METRICS.hotplug.vcpu_hotplug_request_count.inc();
let config = serde_json::from_slice::<VcpuHotPlugConfig>(body.raw()).map_err(|err| {
METRICS.hotplug.vcpu_hotplug_request_fails.inc();
err
})?;

let mut parsed_req = ParsedRequest::new_sync(VmmAction::UpdateVmConfiguration(machine_config_update));
Ok(parsed_req)

Err(RequestError::Generic(StatusCode::BadRequest, "Placeholder".to_string()))
}

#[cfg(test)]
mod tests {

use hotplug::{parse_put_hotplug, parse_put_vcpu_hotplug};

use super::super::*;


#[test]
fn test_parse_put_hotplug() {
// Case 1. Invalid resource type
parse_put_hotplug(&Body::new("invalid body"), Some("invalid")).unwrap_err();

// Case 2. No resource type
parse_put_hotplug(&Body::new("invalid body"), None).unwrap_err();

// Case 3. vCPU Resource
let body = r#"{
"vcpu_count": 8
}"#;
parse_put_hotplug(&Body::new(body), Some("vcpu")).unwrap();
}

#[test]
fn test_parse_put_vcpu_hotplug() {

// Case 1. invalid payload
parse_put_vcpu_hotplug(&Body::new("invalid")).unwrap_err();

// Case 2. invalid core count (too low)
let body = r#"{
"vcpu_count" : 0,
}"#;
parse_put_vcpu_hotplug(&Body::new(body)).unwrap_err();

// Case 3. invalid core count (too high)
let body = r#"{
"vcpu_count" : 33,
}"#;
parse_put_vcpu_hotplug(&Body::new(body)).unwrap_err();

// Case 4. valid core count
let body = r#"{
"vcpu_count" : 8,
}"#;
assert!(METRICS.hotplug.vcpu_hotplug_request_count > 0 && METRICS.hotplug.vcpu_hotplug_request_fails == 0);
}
}
28 changes: 28 additions & 0 deletions src/vmm/src/logger/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,10 @@ pub struct PutRequestsMetrics {
pub drive_count: SharedIncMetric,
/// Number of failures in attaching a block device.
pub drive_fails: SharedIncMetric,
/// Number of PUTs for hotplugging
pub hotplug: SharedIncMetric,
/// Number of failures for hotplugging.
pub hotplug_fails: SharedIncMetric,
/// Number of PUTs for initializing the logging system.
pub logger_count: SharedIncMetric,
/// Number of failures in initializing the logging system.
Expand Down Expand Up @@ -449,6 +453,8 @@ impl PutRequestsMetrics {
boot_source_fails: SharedIncMetric::new(),
drive_count: SharedIncMetric::new(),
drive_fails: SharedIncMetric::new(),
hotplug: SharedIncMetric::new(),
hotplug_fails: SharedIncMetric::new(),
logger_count: SharedIncMetric::new(),
logger_fails: SharedIncMetric::new(),
machine_cfg_count: SharedIncMetric::new(),
Expand Down Expand Up @@ -824,6 +830,25 @@ impl VmmMetrics {
}
}


/// Metrics specific to hotplugging
#[derive(Debug, Default, Serialize)]
pub struct HotplugMetrics {
pub vcpu_hotplug_request_count: SharedIncMetric,
pub vcpu_hotplug_request_fails: SharedIncMetric,
}

impl HotplugMetrics {
/// Const default construction.
pub const fn new() -> Self {
Self {
vcpu_hotplug_request_count: SharedIncMetric::new(),
vcpu_hotplug_request_fails: SharedIncMetric::new(),
}
}
}

// The sole purpose of this struct is to produce an UTC timestamp when an instance is serialized.
#[derive(Debug, Default)]
struct SerializeToUtcTimestampMs;
Expand Down Expand Up @@ -887,6 +912,8 @@ pub struct FirecrackerMetrics {
pub deprecated_api: DeprecatedApiMetrics,
/// Metrics related to API GET requests.
pub get_api_requests: GetRequestsMetrics,
/// Metrics related to hot-plugging.
pub hotplug: HotplugMetrics,
#[serde(flatten)]
/// Metrics related to the legacy device.
pub legacy_dev_ser: LegacyDevMetricsSerializeProxy,
Expand Down Expand Up @@ -931,6 +958,7 @@ impl FirecrackerMetrics {
block_ser: BlockMetricsSerializeProxy {},
deprecated_api: DeprecatedApiMetrics::new(),
get_api_requests: GetRequestsMetrics::new(),
hotplug: HotplugMetrics::new(),
legacy_dev_ser: LegacyDevMetricsSerializeProxy {},
latencies_us: PerformanceMetrics::new(),
logger: LoggerSystemMetrics::new(),
Expand Down
8 changes: 6 additions & 2 deletions src/vmm/src/vmm_config/hotplug.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use serde::{Deserialize, Serialize};

/// Firecracker aims to support small scale workloads only, so limit the maximum
/// vCPUs supported.
pub const MAX_SUPPORTED_VCPUS: u8 = 32;

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
/// Errors associated with hot-plugging vCPUs
#[derive(Debug)]
pub enum VcpuHotPlugConfigError {
/// The number of vCPUs must be greater than 0, less than {MAX_SUPPORTED_VCPUS:} and must be 1 or an even number if SMT is enabled.
InvalidVcpuCount,
}

/// Config for hotplugging vCPUS
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct VcpuHotPlugConfig {
/// Number of vcpus to start.
pub vcpu_count: u8,
Expand Down

0 comments on commit d2d6d41

Please sign in to comment.