From 7350c65d4b45bd0022368fae2146a6d308a17e01 Mon Sep 17 00:00:00 2001 From: Babis Chalios Date: Thu, 21 Sep 2023 15:02:19 +0000 Subject: [PATCH] snapshot: deprecate forward compatibility Forward compatibility refers to the ability of Firecracker to create snapshots for older version formats. This feature is now deprecated and it will be removed in a subsequent release. Snapshot support is in developer preview, so dropping support for it does not require us to increase Firecracker's major version. In practice, deprecating this feature means that we deprecate the `version` field of the `PUT /snapshot/create` request. This commit, adds the "deprecated" header in the response of the endpoint if `version` is defined and documents the deprecation in CHANGELOG and snapshot documentation. Signed-off-by: Babis Chalios --- CHANGELOG.md | 3 ++ docs/snapshotting/snapshot-support.md | 5 +++ src/api_server/src/request/snapshot.rs | 33 +++++++++++++++---- src/api_server/swagger/firecracker.yaml | 3 +- .../integration_tests/functional/test_api.py | 21 ++++++++++++ 5 files changed, 58 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61f0c26a66b4..b1a0773c52eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,9 @@ - Changed the dump feature of `cpu-template-helper` tool not to enumerate program counter (PC) on ARM because it is determined by the given kernel image and it is useless in the custom CPU template context. +- The ability to create snapshots for an older version of Firecracker is now + deprecated. As a result, the `version` body field in `PUT` on + `/snapshot/create` request in deprecated. ### Fixed diff --git a/docs/snapshotting/snapshot-support.md b/docs/snapshotting/snapshot-support.md index 2d16bdd64611..b811035e7231 100644 --- a/docs/snapshotting/snapshot-support.md +++ b/docs/snapshotting/snapshot-support.md @@ -175,6 +175,11 @@ The Firecracker snapshotting implementation offers support for snapshot versioni (`cross-version snapshots`) in the following contexts: - Saving snapshots at older versions + + **DEPRECATED**: This feature is deprecated starting with version 1.5.0. It + will be removed in subsequent release. After dropping support, Firecracker + will be able to create snapshots only for the version supported by the + Firecracker binary that launched the microVM and not for older versions. This refers to being able to create a snapshot with any version in the `[N, N + o]` interval, while running Firecracker version `N+o`. diff --git a/src/api_server/src/request/snapshot.rs b/src/api_server/src/request/snapshot.rs index 3563c85f9b9d..aef70a8b9559 100644 --- a/src/api_server/src/request/snapshot.rs +++ b/src/api_server/src/request/snapshot.rs @@ -1,7 +1,7 @@ // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -use logger::{IncMetric, METRICS}; +use logger::{debug, IncMetric, METRICS}; use serde::de::Error as DeserializeError; use vmm::vmm_config::snapshot::{ CreateSnapshotParams, LoadSnapshotConfig, LoadSnapshotParams, MemBackendConfig, MemBackendType, @@ -14,6 +14,9 @@ use crate::request::{Body, Method, StatusCode}; /// Deprecation message for the `mem_file_path` field. const LOAD_DEPRECATION_MESSAGE: &str = "PUT /snapshot/load: mem_file_path field is deprecated."; +/// Deprecation message for the `version` field. +const CREATE_WITH_VERSION_DEPRECATION_MESSAGE: &str = + "PUT /snapshot/create: 'version' field is deprecated."; /// None of the `mem_backend` or `mem_file_path` fields has been specified. pub const MISSING_FIELD: &str = "missing field: either `mem_backend` or `mem_file_path` is required"; @@ -28,9 +31,7 @@ pub(crate) fn parse_put_snapshot( ) -> Result { match request_type_from_path { Some(request_type) => match request_type { - "create" => Ok(ParsedRequest::new_sync(VmmAction::CreateSnapshot( - serde_json::from_slice::(body.raw())?, - ))), + "create" => parse_put_snapshot_create(body), "load" => parse_put_snapshot_load(body), _ => Err(Error::InvalidPathMethod( format!("/snapshot/{}", request_type), @@ -53,6 +54,23 @@ pub(crate) fn parse_patch_vm_state(body: &Body) -> Result } } +fn parse_put_snapshot_create(body: &Body) -> Result { + let snapshot_config = serde_json::from_slice::(body.raw())?; + let uses_deprecated_version_field = snapshot_config.version.is_some(); + + let mut parsed_req = ParsedRequest::new_sync(VmmAction::CreateSnapshot(snapshot_config)); + // `version` field is deprecated as a parameter for `CreateSnapshotParams`. + // Add a deprecation message if the request includes the parameter. + if uses_deprecated_version_field { + METRICS.deprecated_api.deprecated_http_api_calls.inc(); + parsed_req + .parsing_info() + .append_deprecation_message(CREATE_WITH_VERSION_DEPRECATION_MESSAGE); + } + + Ok(parsed_req) +} + fn parse_put_snapshot_load(body: &Body) -> Result { let snapshot_config = serde_json::from_slice::(body.raw())?; @@ -134,8 +152,11 @@ mod tests { version: Some(Version::new(0, 23, 0)), }; - match vmm_action_from_request(parse_put_snapshot(&Body::new(body), Some("create")).unwrap()) - { + let parsed_request = parse_put_snapshot(&Body::new(body), Some("create")).unwrap(); + match depr_action_from_req( + parsed_request, + Some(CREATE_WITH_VERSION_DEPRECATION_MESSAGE.to_string()), + ) { VmmAction::CreateSnapshot(cfg) => assert_eq!(cfg, expected_cfg), _ => panic!("Test failed."), } diff --git a/src/api_server/swagger/firecracker.yaml b/src/api_server/swagger/firecracker.yaml index 4cfb61265619..e2290b53b23c 100644 --- a/src/api_server/swagger/firecracker.yaml +++ b/src/api_server/swagger/firecracker.yaml @@ -1179,7 +1179,8 @@ definitions: type: string description: The microVM version for which we want to create the snapshot. - It is optional and it defaults to the current version. + It is optional and it defaults to the current version. This parameter + has been deprecated and it will be removed in future Firecracker release. SnapshotLoadParams: type: object diff --git a/tests/integration_tests/functional/test_api.py b/tests/integration_tests/functional/test_api.py index 55df8d887337..13731c3d3da0 100644 --- a/tests/integration_tests/functional/test_api.py +++ b/tests/integration_tests/functional/test_api.py @@ -1261,6 +1261,27 @@ def test_map_private_seccomp_regression(test_microvm_with_api): test_microvm.api.mmds.put(**data_store) +def test_negative_snapshot_create_api(microvm_factory, guest_kernel, rootfs): + """ + Test snapshot create API. + """ + + vm = microvm_factory.build(guest_kernel, rootfs) + vm.spawn() + vm.basic_config() + vm.start() + + # Specifying `version` in the create API is deprecated + vm.pause() + response = vm.api.snapshot_create.put( + mem_file_path="mem", + snapshot_path="vmstate", + snapshot_type="Full", + version="1.4.0", + ) + assert response.headers["deprecation"] + assert "PUT /snapshot/create: version field is deprecated." in vm.log_data + # pylint: disable=protected-access def test_negative_snapshot_load_api(microvm_factory): """