Skip to content
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

stop logging cloud_init_bytes in sled-agent #6439

Merged
merged 4 commits into from
Aug 27, 2024
Merged

Conversation

iliana
Copy link
Contributor

@iliana iliana commented Aug 26, 2024

aka "want sled-agent to stop screaming at base64 floppy disks"

Fixes #6387.

  1. Create a NoDebug wrapper struct for this purpose in omicron-common. (Note that the OpenAPI schema for sled-agent does not change; schemars seems to honor #[serde(transparent)].)
  2. Apply NoDebug inside the cloud_init_bytes Option. Thus we log everything else about the instance hardware, and whether or not there is cidata, but not the cidata itself.
  3. Demote an INFO-level log of the Propolis client's InstanceEnsureRequest to DEBUG.

@@ -118,3 +118,22 @@ where
async fn never_bail() -> Result<bool, Error> {
Ok(false)
}

/// A wrapper struct that does nothing other than elide the inner value from
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote https://docs.rs/debug-ignore a bit ago which we use :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trick is that it must also implement JsonSchema for this particular use case, and anything else we ever want to use it in a struct for as well. For that reason it seems to make sense to keep it within Omicron so we can adjust it as needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sighhhh, yeah.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Could you add a comment about this?)

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for doing this, the giant base64 strings were getting on my nerves a bit!

Comment on lines +131 to +132
#[repr(transparent)]
#[serde(transparent)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

world's most transparent type :)

@@ -63,7 +64,7 @@ pub struct InstanceHardware {
pub dhcp_config: DhcpConfig,
// TODO: replace `propolis_client::*` with locally-modeled request type
pub disks: Vec<propolis_client::types::DiskRequest>,
pub cloud_init_bytes: Option<String>,
pub cloud_init_bytes: Option<NoDebug<String>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative solution, rather than adding a no-debug wrapper type, could be to manually implement Debug for InstanceHardware using fmt::DebugStruct, and formatting everything normally but skipping the cloud_init_bytes field (or rendering it as Some(..)/None).

I'm not sure which is better off the top of my head --- the wrapper type seems a bit unfortunate: the "actual" type is Option<String>, and it's kinda sad to change the type just to control formatting behavior. But it might be better in the long run, since we don't have to remember to add any new fields to the manual debug implementation. So, I think this is fine, just felt like talking through alternatives.


Incidentally, there is nice technique for avoiding issues where new fields aren't added to a manual Debug implementation, though (credit to my friend @cratelyn for this one). You can use a destructuring assignment on the Self type in the Debug impl, like:

impl fmt::Debug for InstanceHardware {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let Self {
            properties,
            nics,
            source_nat,
            ephemeral_ip,
            floating_ips,
            firewall_rules,
            dhcp_config,
            disks,
            cloud_init_bytes,
        } = self;
        f.debug_struct("InstanceHardware")
            .field("properties", properties)
            .field("nics", nics)
            // ... and so on ...
            .finish()
    }
}

and, because the destructuring pattern binds all the fields (since it doesn't have a ..), any newly-added field will cause it to fail to compile, serving as a nice reminder to add the new field to the Debug impl. But, this is still more work than #[derive(Debug)], so...

Copy link
Contributor

@sunshowers sunshowers Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I prefer the wrapper struct over the two other alternatives I'm aware of, the manual impl you mentioned and the derive-more crate. But there are definitely places where I'd use one of the other approaches.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, the wrapper struct is fine with me!

@iliana iliana enabled auto-merge (squash) August 27, 2024 18:39
@iliana iliana merged commit a24fa8c into main Aug 27, 2024
22 checks passed
@iliana iliana deleted the iliana/cidata-screaming branch August 27, 2024 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Sled-agent could demote printing cloud init bytes in the instance-ensure request to debug level
3 participants