Skip to content

Commit 4ff2c99

Browse files
committed
vmm: Deprecate static CPU templates
Deprecate the `cpu_template` field in the `/machine-config` API, which is used to set static CPU templates. Users can use custom CPU templates as an alternative. To differentiate between explicitly specifying `None` and not specifying anything, wrap the `cpu_template` of the `MachineConfig` with `Option`. With this, it can notify the deprecation of only users using the field. Signed-off-by: Takahiro Itazuri <[email protected]>
1 parent 915f56b commit 4ff2c99

File tree

7 files changed

+158
-13
lines changed

7 files changed

+158
-13
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@
4848
- Added support for the /dev/userfaultfd device available on linux kernels >=
4949
6.1. This is the default for creating UFFD handlers on these kernel versions.
5050
If it is unavailable, Firecracker falls back to the userfaultfd syscall.
51+
- Deprecated `cpu_template` field in `PUT` and `PATCH` request on `/machine-config`
52+
API, which is used to set a static CPU template. Custom CPU templates added in
53+
v1.4.0 are available as an improved iteration of the static CPU templates. For
54+
more information about the transition from static CPU templates to custom CPU
55+
templates, please refer [here](https://github.com./firecracker-microvm/firecracker/discussions/4135).
5156

5257
### Fixed
5358

docs/cpu_templates/cpu-templates.md

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ Firecracker supports two types of CPU templates:
3434
- Custom CPU templates - users can create their own CPU templates in json
3535
format and pass them to Firecracker
3636

37+
> **Note**
38+
Staitc CPU templates are deprecated starting from v1.5.0 and will be removed in
39+
accordance with our deprecation policy. Even after the removal, custom CPU
40+
templates are available as an improved iteration of static CPU templates. For
41+
more information about the transition from static CPU templates to custom CPU
42+
templates, please refer [here](https://github.com./firecracker-microvm/firecracker/discussions/4135).
43+
3744
> **Note**
3845
CPU templates for ARM (both static and custom) require the following patch
3946
to be available in the host kernel: [Support writable CPU ID registers from userspace](https://lore.kernel.org/kvm/[email protected]/#t).

src/api_server/src/request/machine_configuration.rs

+100-9
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,25 @@ pub(crate) fn parse_put_machine_config(body: &Body) -> Result<ParsedRequest, Err
2020
err
2121
})?;
2222

23+
// Check for the presence of deprecated `cpu_template` field.
24+
let mut deprecation_message = None;
25+
if config.cpu_template.is_some() {
26+
// `cpu_template` field in request is deprecated.
27+
METRICS.deprecated_api.deprecated_http_api_calls.inc();
28+
deprecation_message = Some("PUT /machine-config: cpu_template field is deprecated.");
29+
}
30+
31+
// Convert `MachineConfig` to `MachineConfigUpdate`.
2332
let config_update = MachineConfigUpdate::from(config);
2433

25-
Ok(ParsedRequest::new_sync(VmmAction::UpdateVmConfiguration(
26-
config_update,
27-
)))
34+
// Construct the `ParsedRequest` object.
35+
let mut parsed_req = ParsedRequest::new_sync(VmmAction::UpdateVmConfiguration(config_update));
36+
// If `cpu_template` was present, set the deprecation message in `parsing_info`.
37+
if let Some(msg) = deprecation_message {
38+
parsed_req.parsing_info().append_deprecation_message(msg);
39+
}
40+
41+
Ok(parsed_req)
2842
}
2943

3044
pub(crate) fn parse_patch_machine_config(body: &Body) -> Result<ParsedRequest, Error> {
@@ -39,17 +53,30 @@ pub(crate) fn parse_patch_machine_config(body: &Body) -> Result<ParsedRequest, E
3953
return method_to_error(Method::Patch);
4054
}
4155

42-
Ok(ParsedRequest::new_sync(VmmAction::UpdateVmConfiguration(
43-
config_update,
44-
)))
56+
// Check for the presence of deprecated `cpu_template` field.
57+
let mut deprecation_message = None;
58+
if config_update.cpu_template.is_some() {
59+
// `cpu_template` field in request is deprecated.
60+
METRICS.deprecated_api.deprecated_http_api_calls.inc();
61+
deprecation_message = Some("PATCH /machine-config: cpu_template field is deprecated.");
62+
}
63+
64+
// Construct the `ParsedRequest` object.
65+
let mut parsed_req = ParsedRequest::new_sync(VmmAction::UpdateVmConfiguration(config_update));
66+
// If `cpu_template` was present, set the deprecation message in `parsing_info`.
67+
if let Some(msg) = deprecation_message {
68+
parsed_req.parsing_info().append_deprecation_message(msg);
69+
}
70+
71+
Ok(parsed_req)
4572
}
4673

4774
#[cfg(test)]
4875
mod tests {
4976
use vmm::cpu_config::templates::StaticCpuTemplate;
5077

5178
use super::*;
52-
use crate::parsed_request::tests::vmm_action_from_request;
79+
use crate::parsed_request::tests::{depr_action_from_req, vmm_action_from_request};
5380

5481
#[test]
5582
fn test_parse_get_machine_config_request() {
@@ -79,6 +106,24 @@ mod tests {
79106
"vcpu_count": 8,
80107
"mem_size_mib": 1024
81108
}"#;
109+
let expected_config = MachineConfigUpdate {
110+
vcpu_count: Some(8),
111+
mem_size_mib: Some(1024),
112+
smt: Some(false),
113+
cpu_template: None,
114+
track_dirty_pages: Some(false),
115+
};
116+
117+
match vmm_action_from_request(parse_put_machine_config(&Body::new(body)).unwrap()) {
118+
VmmAction::UpdateVmConfiguration(config) => assert_eq!(config, expected_config),
119+
_ => panic!("Test failed."),
120+
}
121+
122+
let body = r#"{
123+
"vcpu_count": 8,
124+
"mem_size_mib": 1024,
125+
"cpu_template": "None"
126+
}"#;
82127
let expected_config = MachineConfigUpdate {
83128
vcpu_count: Some(8),
84129
mem_size_mib: Some(1024),
@@ -102,7 +147,7 @@ mod tests {
102147
vcpu_count: Some(8),
103148
mem_size_mib: Some(1024),
104149
smt: Some(false),
105-
cpu_template: Some(StaticCpuTemplate::None),
150+
cpu_template: None,
106151
track_dirty_pages: Some(true),
107152
};
108153

@@ -155,7 +200,7 @@ mod tests {
155200
vcpu_count: Some(8),
156201
mem_size_mib: Some(1024),
157202
smt: Some(true),
158-
cpu_template: Some(StaticCpuTemplate::None),
203+
cpu_template: None,
159204
track_dirty_pages: Some(true),
160205
};
161206

@@ -209,4 +254,50 @@ mod tests {
209254
let body = r#"{}"#;
210255
assert!(parse_patch_machine_config(&Body::new(body)).is_err());
211256
}
257+
258+
#[test]
259+
fn test_depr_cpu_template_in_put_req() {
260+
// Test that the deprecation message is shown when `cpu_template` is specified.
261+
let body = r#"{
262+
"vcpu_count": 8,
263+
"mem_size_mib": 1024,
264+
"cpu_template": "None"
265+
}"#;
266+
depr_action_from_req(
267+
parse_put_machine_config(&Body::new(body)).unwrap(),
268+
Some("PUT /machine-config: cpu_template field is deprecated.".to_string()),
269+
);
270+
271+
// Test that the deprecation message is not shown when `cpu_template` is not specified.
272+
let body = r#"{
273+
"vcpu_count": 8,
274+
"mem_size_mib": 1024
275+
}"#;
276+
let (_, mut parsing_info) = parse_put_machine_config(&Body::new(body))
277+
.unwrap()
278+
.into_parts();
279+
assert!(parsing_info.take_deprecation_message().is_none());
280+
}
281+
282+
#[test]
283+
fn test_depr_cpu_template_in_patch_req() {
284+
// Test that the deprecation message is shown when `cpu_template` is specified.
285+
let body = r#"{
286+
"vcpu_count": 8,
287+
"cpu_template": "None"
288+
}"#;
289+
depr_action_from_req(
290+
parse_patch_machine_config(&Body::new(body)).unwrap(),
291+
Some("PATCH /machine-config: cpu_template field is deprecated.".to_string()),
292+
);
293+
294+
// Test that the deprecation message is not shown when `cpu_template` is not specified.
295+
let body = r#"{
296+
"vcpu_count": 8
297+
}"#;
298+
let (_, mut parsing_info) = parse_patch_machine_config(&Body::new(body))
299+
.unwrap()
300+
.into_parts();
301+
assert!(parsing_info.take_deprecation_message().is_none());
302+
}
212303
}

src/api_server/swagger/firecracker.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,8 @@ definitions:
826826
description:
827827
The CPU Template defines a set of flags to be disabled from the microvm so that
828828
the features exposed to the guest are the same as in the selected instance type.
829+
This parameter has been deprecated and it will be removed in accordance with our
830+
policy.
829831
enum:
830832
- C3
831833
- T2

src/vmm/src/cpu_config/templates.rs

+9
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ impl From<&Option<CpuTemplateType>> for StaticCpuTemplate {
7272
}
7373
}
7474

75+
impl From<&CpuTemplateType> for StaticCpuTemplate {
76+
fn from(value: &CpuTemplateType) -> Self {
77+
match value {
78+
CpuTemplateType::Static(template) => *template,
79+
CpuTemplateType::Custom(_) => StaticCpuTemplate::None,
80+
}
81+
}
82+
}
83+
7584
impl<'a> TryFrom<&'a [u8]> for CustomCpuTemplate {
7685
type Error = serde_json::Error;
7786

src/vmm/src/vmm_config/machine_config.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ pub struct MachineConfig {
4040
#[serde(default, deserialize_with = "deserialize_smt")]
4141
pub smt: bool,
4242
/// A CPU template that it is used to filter the CPU features exposed to the guest.
43-
#[serde(default, skip_serializing_if = "StaticCpuTemplate::is_none")]
44-
pub cpu_template: StaticCpuTemplate,
43+
#[serde(default, skip_serializing_if = "Option::is_none")]
44+
pub cpu_template: Option<StaticCpuTemplate>,
4545
/// Enables or disables dirty page tracking. Enabling allows incremental snapshots.
4646
#[serde(default)]
4747
pub track_dirty_pages: bool,
@@ -122,7 +122,7 @@ impl From<MachineConfig> for MachineConfigUpdate {
122122
vcpu_count: Some(cfg.vcpu_count),
123123
mem_size_mib: Some(cfg.mem_size_mib),
124124
smt: Some(cfg.smt),
125-
cpu_template: Some(cfg.cpu_template),
125+
cpu_template: cfg.cpu_template,
126126
track_dirty_pages: Some(cfg.track_dirty_pages),
127127
}
128128
}
@@ -212,7 +212,7 @@ impl From<&VmConfig> for MachineConfig {
212212
vcpu_count: value.vcpu_count,
213213
mem_size_mib: value.mem_size_mib,
214214
smt: value.smt,
215-
cpu_template: (&value.cpu_template).into(),
215+
cpu_template: value.cpu_template.as_ref().map(|template| template.into()),
216216
track_dirty_pages: value.track_dirty_pages,
217217
}
218218
}

tests/integration_tests/functional/test_api.py

+31
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,37 @@ def test_api_machine_config(test_microvm_with_api):
428428
assert json["machine-config"]["smt"] is False
429429

430430

431+
def test_negative_machine_config_api(test_microvm_with_api):
432+
"""
433+
Test the deprecated `cpu_template` field in PUT and PATCH requests on
434+
`/machine-config` API is handled correctly.
435+
436+
When using the `cpu_template` field (even if the value is "None"), the HTTP
437+
response header should have "Deprecation: true".
438+
"""
439+
test_microvm = test_microvm_with_api
440+
test_microvm.spawn()
441+
442+
# Use `cpu_template` field in PUT /machine-config
443+
response = test_microvm.api.machine_config.put(
444+
vcpu_count=2,
445+
mem_size_mib=256,
446+
cpu_template="None",
447+
)
448+
assert response.headers["deprecation"]
449+
assert (
450+
"PUT /machine-config: cpu_template field is deprecated."
451+
in test_microvm.log_data
452+
)
453+
454+
# Use `cpu_template` field in PATCH /machine-config
455+
response = test_microvm.api.machine_config.patch(cpu_template="None")
456+
assert (
457+
"PATCH /machine-config: cpu_template field is deprecated."
458+
in test_microvm.log_data
459+
)
460+
461+
431462
@nonci_on_arm
432463
def test_api_cpu_config(test_microvm_with_api, custom_cpu_template):
433464
"""

0 commit comments

Comments
 (0)