-
Notifications
You must be signed in to change notification settings - Fork 40
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
Allow different versions for differently signed RoT images #5580
Conversation
b557ccf
to
5cd0db8
Compare
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.
Had a quick look, generally looks good!
// version at builder time (builder time is not async) | ||
let image_a = rot_a_data | ||
.reader_stream() | ||
.and_then(|stream| async { |
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.
Could this use a .await
rather than a future combinator? In general, .await
is preferable -- it's easier to understand, particularly because .and_then
exists both on futures and on results. (There are exceptions where future combinators make sense, but this doesn't seem to be one of them.)
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.
I was going off of what wicketd was doing (https://github.com/oxidecomputer/omicron/blob/main/wicketd/src/update_tracker.rs#L1679-L1696) but I'm fine with changing it for readability.
tokio_util::io::StreamReader::new(stream) | ||
.read_to_end(&mut buf) | ||
.await | ||
.unwrap(); |
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.
These are extracted as files on disk, so I believe they can produce errors. Even if they can't, it would be good to replace the unwrap()
with an expect("justification")
.
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.
wicketd mentions this can be an I/O error https://github.com/oxidecomputer/omicron/blob/main/wicketd/src/update_tracker.rs#L1690 . I'll match that here.
.and_then(|stream| async { | ||
let mut buf = Vec::with_capacity(rot_b_data.file_size()); | ||
tokio_util::io::StreamReader::new(stream) | ||
.read_to_end(&mut buf) | ||
.await | ||
.unwrap(); | ||
Ok(buf) | ||
}) | ||
.await | ||
.unwrap(); |
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.
Same comments about both using .await
and bubbling up errors here.
let archive_a = make_fake_rot_image(sign, board); | ||
let archive_b = make_fake_rot_image(sign, board); |
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.
haha I was wondering when this would become less random, thanks for doing this :)
5cd0db8
to
bd58a59
Compare
#[error("error creating reader stream")] | ||
CreateReaderStream(#[source] anyhow::Error), |
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.
Not sure the opinion on adding new errors here
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.
Adding new errors (when needed) is good 👍
#[error("error creating reader stream")] | ||
CreateReaderStream(#[source] anyhow::Error), |
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.
Adding new errors (when needed) is good 👍
tokio_util::io::StreamReader::new(image_a_stream) | ||
.read_to_end(&mut image_a) | ||
.await | ||
.expect("failed to read RoT image a"); |
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.
I don't think we can .expect()
these - reader_stream()
returns streams that are backed by tokio::fs::File
s, which can fail at runtime. Probably need something like a
RepositoryError::ReadExtractedArchive {
artifact: ArtifactHashId,
#[source]
error: std::io::Error,
}
variant to use here?
return Err(RepositoryError::ReadHubrisCabooseBoard { id, error }); | ||
} | ||
}; | ||
let sign = match std::str::from_utf8(sign) { |
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.
Do we use the fact that we're storing sign
as a String
anywhere? I'm wondering if this conversion is necessary at all, or if we could store (ArtifactId, Vec<u8>)
instead.
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.
General logic looks great! Just a few comments + co-signing John's comments.
tokio_util::io::StreamReader::new(image_b_stream) | ||
.read_to_end(&mut image_b) | ||
.await | ||
.expect("failed to read RoT image b"); |
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.
Yeah same here -- we should produce an error.
let logctx = test_setup_log("test_multi_rot_version"); | ||
|
||
let mut plan_builder = | ||
UpdatePlanBuilder::new("0.0.0".parse().unwrap(), &logctx.log) |
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.
Can this use VERSION_0
as well?
@@ -112,6 +113,7 @@ pub struct UpdatePlanBuilder<'a> { | |||
// The by_id and by_hash maps, and metadata, used in `ArtifactsWithPlan`. |
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.
This comment should be updated.
@@ -112,6 +113,7 @@ pub struct UpdatePlanBuilder<'a> { | |||
// The by_id and by_hash maps, and metadata, used in `ArtifactsWithPlan`. | |||
by_id: BTreeMap<ArtifactId, Vec<ArtifactHashId>>, | |||
by_hash: HashMap<ArtifactHashId, ExtractedArtifactDataHandle>, | |||
by_sign: HashMap<(KnownArtifactKind, String), Vec<ArtifactId>>, |
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.
What does the key stand for?
What do you think about turning this into a struct with named fields?
by_sign
seems to only contain Hubris artifacts, is that right? If so could this be documented here?
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.
I'll clarify this with some rework and comments
return Err(RepositoryError::ReadHubrisCaboose { id, error }); | ||
} | ||
}; | ||
let sign = match caboose.sign() { |
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.
hmm, what kind of values does sign
have? Is it one of a small fixed set of values, or is it arbitrary?
is it worth wrapping the sign in a newtype (probably in the caboose API I guess)?
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.
It's a &[u8]
(https://github.com/oxidecomputer/hubtools/blob/main/hubtools/src/caboose.rs#L47-L49) although as @jgallagher noted below the extra step of conversion to a string is probably unnecessary except for error cases.
Currently we restrict all RoT archives for {Gimlet, PSC, Sidecar} to be the same version. This restricts us to having staging and production images to be the same version. What we actually want is all archives for a particular kind _signed with the same key_ to have the same version.
24de5b0
to
e7c16a0
Compare
e7c16a0
to
463aa0d
Compare
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.
LGTM 👍
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.
agreed, looks great!
Currently we restrict all RoT archives for {Gimlet, PSC, Sidecar} to be the same version. This restricts us to having staging and production images to be the same version. What we actually want is all archives for a particular kind signed with the same key to have the same version.