-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't allow downgrading the system target release #7807
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -6442,14 +6442,30 @@ impl NexusExternalApi for NexusExternalApiImpl { | |||||
crate::context::op_context_for_external_api(&rqctx).await?; | ||||||
let params = body.into_inner(); | ||||||
let system_version = params.system_version; | ||||||
|
||||||
let current_target_release = | ||||||
nexus.datastore().target_release_get_current(&opctx).await?; | ||||||
let view = nexus | ||||||
.datastore() | ||||||
.target_release_view(&opctx, ¤t_target_release) | ||||||
.await?; | ||||||
if let views::TargetReleaseSource::SystemVersion { version } = | ||||||
view.release_source | ||||||
{ | ||||||
if version > system_version { | ||||||
return Err(HttpError::for_bad_request( | ||||||
None, | ||||||
"can't downgrade system".into(), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I'm imagining an end user might see this message and want to make sure it's clear what's going on and what they've done wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, thanks! Also added in c2233b9. |
||||||
)); | ||||||
} | ||||||
} | ||||||
|
||||||
let tuf_repo_id = nexus | ||||||
.datastore() | ||||||
.update_tuf_repo_get(&opctx, system_version.into()) | ||||||
.await? | ||||||
.repo | ||||||
.id; | ||||||
let current_target_release = | ||||||
nexus.datastore().target_release_get_current(&opctx).await?; | ||||||
let next_target_release = | ||||||
nexus_db_model::TargetRelease::new_system_version( | ||||||
¤t_target_release, | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# This is an artifact manifest that generates fake entries for all components. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about calling this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
# This is completely non-functional and is only useful for testing archive | ||
# extraction in other parts of the repository. | ||
|
||
system_version = "0.0.0" | ||
|
||
[[artifact.gimlet_sp]] | ||
name = "fake-gimlet-sp" | ||
version = "0.0.0" | ||
source = { kind = "fake", size = "1MiB" } | ||
|
||
[[artifact.gimlet_rot]] | ||
name = "fake-gimlet-rot" | ||
version = "0.0.0" | ||
[artifact.gimlet_rot.source] | ||
kind = "composite-rot" | ||
archive_a = { kind = "fake", size = "512KiB" } | ||
archive_b = { kind = "fake", size = "512KiB" } | ||
|
||
[[artifact.host]] | ||
name = "fake-host" | ||
version = "0.0.0" | ||
[artifact.host.source] | ||
kind = "composite-host" | ||
phase_1 = { kind = "fake", size = "512KiB" } | ||
phase_2 = { kind = "fake", size = "1MiB" } | ||
|
||
[[artifact.trampoline]] | ||
name = "fake-trampoline" | ||
version = "0.0.0" | ||
[artifact.trampoline.source] | ||
kind = "composite-host" | ||
phase_1 = { kind = "fake", size = "512KiB" } | ||
phase_2 = { kind = "fake", size = "1MiB" } | ||
|
||
[[artifact.control_plane]] | ||
name = "fake-control-plane" | ||
version = "0.0.0" | ||
[artifact.control_plane.source] | ||
kind = "composite-control-plane" | ||
zones = [ | ||
{ kind = "fake", name = "zone1", size = "1MiB" }, | ||
{ kind = "fake", name = "zone2", size = "1MiB" }, | ||
] | ||
|
||
[[artifact.psc_sp]] | ||
name = "fake-psc-sp" | ||
version = "0.0.0" | ||
source = { kind = "fake", size = "1MiB" } | ||
|
||
[[artifact.psc_rot]] | ||
name = "fake-psc-rot" | ||
version = "0.0.0" | ||
[artifact.psc_rot.source] | ||
kind = "composite-rot" | ||
archive_a = { kind = "fake", size = "512KiB" } | ||
archive_b = { kind = "fake", size = "512KiB" } | ||
|
||
[[artifact.switch_sp]] | ||
name = "fake-switch-sp" | ||
version = "0.0.0" | ||
source = { kind = "fake", size = "1MiB" } | ||
|
||
[[artifact.switch_rot]] | ||
name = "fake-switch-rot" | ||
version = "0.0.0" | ||
[artifact.switch_rot.source] | ||
kind = "composite-rot" | ||
archive_a = { kind = "fake", size = "512KiB" } | ||
archive_b = { kind = "fake", size = "512KiB" } | ||
|
||
[[artifact.gimlet_rot_bootloader]] | ||
name = "fake-gimlet-rot-bootloader" | ||
version = "0.0.0" | ||
source = { kind = "fake", size = "1MiB" } | ||
|
||
[[artifact.psc_rot_bootloader]] | ||
name = "fake-psc-rot-bootloader" | ||
version = "0.0.0" | ||
source = { kind = "fake", size = "1MiB" } | ||
|
||
[[artifact.switch_rot_bootloader]] | ||
name = "fake-switch-rot-bootloader" | ||
version = "0.0.0" | ||
source = { kind = "fake", size = "1MiB" } | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. I like the test, too.
I wonder if this condition needs to be checked transactionally with the update, though? I'm thinking of the time-of-check-to-time-of-use race where say the system is at version 14, the user is trying to update to 15, but someone else comes in and sets it to 16 in the meantime, then we overwrite that with 15. But maybe this is prevented because at L6469 below, we construct the next target release with a generation number of 1 + whatever we just saw (that was version 14), so we'll necessarily fail the database update if someone else comes in in between? If that's the case, could we add a comment here explaining why this race isn't a problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is indeed the case; documented in c2233b9.