feat(snapshot): allow block device path override on restore#5774
feat(snapshot): allow block device path override on restore#5774meAmitPatil wants to merge 1 commit into
Conversation
|
Hi @meAmitPatil, Thanks for the contribution. This is something we'd be interested in supporting, I'll take a look at it in the coming days. In the meantime, would you be able to add python integration tests to this? Something similar to those in #4731 and #5323 should work. Thank you! |
@JamesC1305 Thanks for the reply I've updated the PR with Python integration tests. |
JamesC1305
left a comment
There was a problem hiding this comment.
Overall changes LGTM. A few very small nits, and one suggestion for improving the integration test coverage. The documentation is in a non-obvious place, but we'll plan to refactor it later and merge all the 'overrides' into their own docfile, so no need to worry about it for this PR.
Once you've responded to my feedback RE integ tests, I'll approve a run and we can go from there. Thanks!
| BlockState::Virtio(virtio_block_state) => virtio_block_state.virtio_state.activated, | ||
| BlockState::VhostUser(vhost_user_block_state) => false, | ||
| BlockState::Virtio(state) => state.virtio_state.activated, | ||
| BlockState::VhostUser(_state) => false, |
There was a problem hiding this comment.
Should this be state rather than _state?
|
|
||
| ### Added | ||
|
|
||
| - [#4014](https://github.com/firecracker-microvm/firecracker/issues/4014): Add |
There was a problem hiding this comment.
nit: this should probably link to the resolving PR rather than the issue.
| # The rootfs disk already exists in the snapshot; override its path | ||
| # to the same file (just proving the override mechanism works). | ||
| rootfs_path = str(snapshot.disks["rootfs"]) | ||
| restored_vm.restore_from_snapshot( | ||
| snapshot, | ||
| drive_overrides=[ | ||
| {"drive_id": "rootfs", "path_on_host": rootfs_path}, | ||
| ], | ||
| resume=True, | ||
| ) |
There was a problem hiding this comment.
Can we expand on this? Maybe it would be good to use cp to make a copy of the rootfs with a similar name. That way we can verify that the override behaviour works with a different file (+ inode).
@JamesC1305 Thanks for the review!
|
|
Hi @meAmitPatil, I triggered a run of the integration tests on your PR, here. It seems like there are some issues with style, build and functional tests. Would you be able to address the errors please? You can run the integration tests locally using Thanks, |
83a278b to
29d2c6c
Compare
|
@JamesC1305 I've squashed the commits, fixed the style issues (gitlint, markdown formatting), and fixed the |
Codecov Report❌ Patch coverage is Please upload reports for the commit a23333b to get more accurate results.
Additional details and impacted files@@ Coverage Diff @@
## main #5774 +/- ##
==========================================
- Coverage 82.87% 82.84% -0.04%
==========================================
Files 276 276
Lines 29729 29757 +28
==========================================
+ Hits 24638 24651 +13
- Misses 5091 5106 +15
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Changes all LGTM. Only thing is the patch coverage is slightly low. Would you be able to extend the unit tests a little bit to increase the coverage and make codecov happy? Seems like the biggest gap is in the newly introduced |
29d2c6c to
aa336b4
Compare
aa336b4 to
16c5261
Compare
|
@JamesC1305 Added unit tests for the |
|
Sincere apologies for the delay in getting back to you. Everything looks good to me now. Could you please rebase and fix the merge conflicts? We can then get this merged for you |
16c5261 to
ca0db63
Compare
|
@JamesC1305 Done, rebased on latest main and resolved all conflicts. Ready for merge! |
Manciukic
left a comment
There was a problem hiding this comment.
mostly lgtm, just one extra verification in the integ test, and more clear handling of vhost-user-blk in API and documentation
| {"drive_id": "rootfs", "path_on_host": "/rootfs_override.ext4"}, | ||
| ], | ||
| resume=True, | ||
| ) |
There was a problem hiding this comment.
we should test the device still works after restore (and override)
| path_on_host: | ||
| type: string | ||
| description: | ||
| The new path on the host for the block device's backing file |
There was a problem hiding this comment.
for consistency with the PUT /drive API we should have either path_on_host (virtio) or socket (vhost).
| } | ||
| ] | ||
| }' | ||
| ``` |
There was a problem hiding this comment.
we should mention how this works with vhost-user-blk as well.
ca0db63 to
a6164d5
Compare
|
@Manciukic Thanks for the review! All three points have been addressed.
|
vsock_override was added in PR firecracker-microvm#5323 which merged after v1.15.1. The cherry-pick of drive_overrides (firecracker-microvm#5774) brought references to vsock_override that don't compile against v1.15.1 base. Removed: persist.rs vsock_override processing block, snapshot.rs test struct field.
JamesC1305
left a comment
There was a problem hiding this comment.
Sorry for the delay in getting back to you on this! We have quite a lot of things going on right now.
I just had one quick point about handling block file paths vs socket paths. AFAICT they're mutually exclusive, so an enum would probably be a better way to represent them.
| pub struct DriveOverride { | ||
| /// The ID of the drive to modify | ||
| pub drive_id: String, | ||
| /// The new host path for a virtio-block device's backing file | ||
| #[serde(default, skip_serializing_if = "Option::is_none")] | ||
| pub path_on_host: Option<String>, | ||
| /// The new socket path for a vhost-user-block device's backend | ||
| #[serde(default, skip_serializing_if = "Option::is_none")] | ||
| pub socket: Option<String>, | ||
| } |
There was a problem hiding this comment.
Can we maybe use an enum here instead of allowing both options? They seem mutually exclusive to me.
There was a problem hiding this comment.
This can be simplified further:
#[derive(Debug, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DriveOverrideBacking {
PathOnHost(String),
Socket(String),
}
Allow overriding block device host paths when restoring from a snapshot. This is useful when disk paths are non-deterministic (e.g. container runtimes using devmapper) or when restoring on a different host where the backing file is at a different location. Adds a drive_overrides parameter to the snapshot load API, following the same pattern as the existing network_overrides and vsock_override. Includes Python integration tests that verify the override works with a different file and that an unknown drive_id is rejected. Closes firecracker-microvm#4014 Signed-off-by: Amit Patil <iamitpatil2001@gmail.com>
a6164d5 to
a23333b
Compare
JamesC1305
left a comment
There was a problem hiding this comment.
Just a few small points that I think will clean the code up a little bit more. Almost there!
| pub struct DriveOverride { | ||
| /// The ID of the drive to modify | ||
| pub drive_id: String, | ||
| /// The new host path for a virtio-block device's backing file | ||
| #[serde(default, skip_serializing_if = "Option::is_none")] | ||
| pub path_on_host: Option<String>, | ||
| /// The new socket path for a vhost-user-block device's backend | ||
| #[serde(default, skip_serializing_if = "Option::is_none")] | ||
| pub socket: Option<String>, | ||
| } |
There was a problem hiding this comment.
This can be simplified further:
#[derive(Debug, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DriveOverrideBacking {
PathOnHost(String),
Socket(String),
}
| let applied = match &entry.backing { | ||
| DriveOverrideBacking::PathOnHost { path_on_host } => { | ||
| device_state.set_disk_path(path_on_host) | ||
| } | ||
| DriveOverrideBacking::Socket { socket } => device_state.set_socket_path(socket), | ||
| }; | ||
| if !applied { | ||
| Err(SnapshotStateFromFileError::DriveOverrideMismatch)?; |
There was a problem hiding this comment.
With the enum, we can collapse the two set_*_path functions into a singular one with match. E.g.,
pub fn apply_override(&mut self, backing: &DriveOverrideBacking)
-> Result<(), DriveOverrideMismatch>
{
match (self, backing) {
(BlockState::Virtio(s), DriveOverrideBacking::PathOnHost(p)) => {
s.disk_path = p.clone(); Ok(())
}
(BlockState::VhostUser(s), DriveOverrideBacking::Socket(p)) => {
s.socket_path = p.clone(); Ok(())
}
_ => Err(DriveOverrideMismatch),
}
}
There was a problem hiding this comment.
Could we have small tests for:
- Testing that we can't supply
path_on_hostandsocketat the same time - Testing that an error is returned when
path_on_hostis provided for vhost-user-blk andsocketforvirtio-blk
Allow overriding block device host paths when restoring from a snapshot. This is useful when disk paths are non-deterministic (e.g. container runtimes using devmapper) or when restoring on a different host where the backing file is at a different location.
Adds a
drive_overridesparameter to the snapshot load API, following the same pattern as the existingnetwork_overrides(#4731) andvsock_override(#5323).Closes #4014
License Acceptance
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. For more information on following Developer Certificate of Origin and signing off your commits, please check
CONTRIBUTING.md.PR Checklist
tools/devtool checkbuild --allto verify that the PR passesbuild checks on all supported architectures.
tools/devtool checkstyleto verify that the PR passes theautomated style checks.
how they are solving the problem in a clear and encompassing way.
in the PR.
CHANGELOG.md.Runbook for Firecracker API changes.
integration tests.
TODO.rust-vmm.