nexus-types: add SupportBundleRequest type and Case field#10090
nexus-types: add SupportBundleRequest type and Case field#10090mergeconflict wants to merge 1 commit intomergeconflict/fm-sb-type-relocationfrom
Conversation
d3b67af to
d5d60b3
Compare
2baa491 to
c2191f0
Compare
08b5f84 to
d87449e
Compare
c2191f0 to
e725e86
Compare
d87449e to
7a5224c
Compare
e725e86 to
beef2af
Compare
| pub only_classes: Vec<String>, | ||
| } | ||
|
|
||
| impl fmt::Display for EreportFilters { |
There was a problem hiding this comment.
With apologies for the drive-by style nit on a draft PR: I'd discourage implementing fmt::Display for types like this, based primarily on this discussion in the std lib docs, particularly:
Because a type can only have one Display implementation, it is often preferable to only implement Display when there is a single most “obvious” way that values can be formatted as text.
This has gotten us into some trouble with other types in the past where "type implements Display, so I can easily convert it to a String, so now I can store a String when I should've been storing a stronger type". That doesn't seem particularly likely in this case, but I'd still recommend moving this to a more explicit method or type. Over in Reconfigurator land we have a bunch of helper types that themselves implement Display, but that's their only purpose; e.g.,
omicron/nexus/types/src/deployment.rs
Lines 518 to 522 in afe86cb
There was a problem hiding this comment.
No worries for the drive-by, thanks for looking! I've moved it out of draft now, and I'll figure out how to address your comment tomorrow.
There was a problem hiding this comment.
Yeah, you may notice a similar pattern with the Case pretty-printer actually being a CaseDisplay displayer type --- we also use that to pass through the requested indentation level.
I will note that the display implementation for FM types here is largely in service of OMDB (and perhaps in future other human-facing dev tools), and I will be quite sad if any of us end up trying to round-trip this stuff through a String and back again. But, I think the displayer thingy is generally a good idea, especially if we want to turn this into a bulleted list or something and need to also pass through an indentation or similar.
beef2af to
1f1c514
Compare
…ield Add the SupportBundleRequest type to fm::case and the support_bundles_requested field to Case. Add Display impls for BundleData, BundleDataSelection, SledSelection, and EreportFilters so that case formatting can show the full data selection for each requested support bundle. Add Serialize/Deserialize derives to the support bundle selection types (BundleDataSelection, BundleData, BundleDataCategory, SledSelection, EreportFilters) since SupportBundleRequest contains Option<BundleDataSelection>. Add proptest Arbitrary impls for BundleDataSelection and EreportFilters (in test_utils modules) and a proptest-based serde round-trip test for BundleDataSelection. Add test_case_display coverage for support bundle requests, exercising both data_selection: None and Some with parameterized categories.
1f1c514 to
ad04192
Compare
7a5224c to
3a6ea71
Compare
|
I think that either this branch or |
| writeln!( | ||
| f, | ||
| "{:>indent$}{DATA:<WIDTH$} {selection}\n", | ||
| "", | ||
| )?; |
There was a problem hiding this comment.
how long do you think this list is liable to be? i always try my best to make my omdb command output 80-column-terminal friendly, because i am spiritually very old or something. i won't hold you to this particular bit of mental illness unless you find it entertaining, but if this is liable to be quite long, we might want to bite the bullet and turn it into a multi-line bulleted list or something?
| }) | ||
| .unwrap(); | ||
|
|
||
| use crate::support_bundle::{BundleData, BundleDataSelection}; |
There was a problem hiding this comment.
considered unimportant, but personally i find having the imports way down here a bit weird...
| bundle1_data.insert(BundleData::Reconfigurator); | ||
| bundle1_data.insert(BundleData::SpDumps); | ||
| bundle1_data.insert(BundleData::HostInfo( | ||
| std::collections::HashSet::from([ | ||
| crate::support_bundle::SledSelection::All, | ||
| ]), | ||
| )); | ||
| bundle1_data.insert(BundleData::Ereports( | ||
| crate::fm::ereport::EreportFilters { | ||
| only_classes: vec!["hw.pwr.*".to_string()], | ||
| ..Default::default() | ||
| }, | ||
| )); |
There was a problem hiding this comment.
hmm --- not for this PR, necessarily, but I wonder if, as we start actually making these in more places, we ought to add a builder-type API to BundleDataSelection to construct complicated ones with somewhat less noise?
| pub only_classes: Vec<String>, | ||
| } | ||
|
|
||
| impl fmt::Display for EreportFilters { |
There was a problem hiding this comment.
Yeah, you may notice a similar pattern with the Case pretty-printer actually being a CaseDisplay displayer type --- we also use that to pass through the requested indentation level.
I will note that the display implementation for FM types here is largely in service of OMDB (and perhaps in future other human-facing dev tools), and I will be quite sad if any of us end up trying to round-trip this stuff through a String and back again. But, I think the displayer thingy is generally a good idea, especially if we want to turn this into a bulleted list or something and need to also pass through an indentation or similar.
| match self { | ||
| Self::Reconfigurator => write!(f, "reconfigurator"), | ||
| Self::HostInfo(sleds) => { | ||
| write!(f, "host_info({})", sleds.iter().format(", ")) |
There was a problem hiding this comment.
does sleds.iter().format(", ") allocate a whole String? personally i don't really like when Display impls allocate but maybe this is overly persnickety of me.
The core thing this PR does is:
SupportBundleRequesttype tofm::case(analogous to @hawkw'sAlertRequest), andsupport_bundles_requestedfield toCase(analogous toalerts_requested).There's a lot of ✨ceremony✨ around this small change, though:
DisplayCasehas a sophisticatedimpl Displaythat formats the stuff it contains. So we needDisplayimpls for all the thingsSupportBundleRequesttransitively contains (BundleData, etc.). Here's what this comes out looking like:Since
Caseisserde::Serialize/Deserialize, we also need to add derives toSupportBundleRequestand all the things it transitively contains.Lastly, since we want to have some sort of reasonable round-trip test for the serialization / deserialization, we use proptest to generate arbitrary inputs. This requires
Arbitraryimpls (or functions that returnStrategy) for all the things too.Context: #10062.