From ef473d400b5a36bc896f904755c0c5d4cdab8a3f Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 12:11:02 -0700 Subject: [PATCH 01/18] [ereport] intial types and dropshot API crate --- Cargo.lock | 25 +++++++ Cargo.toml | 5 +- ereport/api/Cargo.toml | 17 +++++ ereport/api/src/lib.rs | 117 ++++++++++++++++++++++++++++++ ereport/types/Cargo.toml | 14 ++++ ereport/types/src/lib.rs | 150 +++++++++++++++++++++++++++++++++++++++ uuid-kinds/src/lib.rs | 1 + 7 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 ereport/api/Cargo.toml create mode 100644 ereport/api/src/lib.rs create mode 100644 ereport/types/Cargo.toml create mode 100644 ereport/types/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 850260587eb..af7fbcfee60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3034,6 +3034,31 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "ereport-types" +version = "0.1.0" +dependencies = [ + "omicron-uuid-kinds", + "schemars", + "serde", + "serde_json", + "uuid", +] + +[[package]] +name = "ereporter-api" +version = "0.1.0" +dependencies = [ + "dropshot 0.16.0", + "ereport-types", + "openapi-manager-types", + "schemars", + "serde", + "serde_json", + "thiserror 1.0.69", + "uuid", +] + [[package]] name = "errno" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index f8ba5598f5c..969fe89816e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ members = [ "dns-server", "dns-server-api", "end-to-end-tests", + "ereport/types", "gateway", "gateway-api", "gateway-cli", @@ -131,7 +132,7 @@ members = [ "wicketd", "wicketd-api", "workspace-hack", - "zone-setup", + "zone-setup", "ereport/api", ] default-members = [ @@ -187,6 +188,7 @@ default-members = [ "dns-server", "dns-server-api", "end-to-end-tests", + "ereport/types", "gateway", "gateway-api", "gateway-cli", @@ -385,6 +387,7 @@ dpd-client = { path = "clients/dpd-client" } dropshot = { version = "0.16.0", features = [ "usdt-probes" ] } dyn-clone = "1.0.19" either = "1.14.0" +ereport-types = { path = "ereport/types" } expectorate = "1.1.0" fatfs = "0.3.6" filetime = "0.2.25" diff --git a/ereport/api/Cargo.toml b/ereport/api/Cargo.toml new file mode 100644 index 00000000000..648648581d9 --- /dev/null +++ b/ereport/api/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "ereporter-api" +version = "0.1.0" +edition = "2024" + +[dependencies] +ereport-types.workspace = true +dropshot.workspace = true +openapi-manager-types.workspace = true +schemars.workspace = true +serde.workspace = true +serde_json.workspace = true +thiserror.workspace = true +uuid.workspace = true + +[lints] +workspace = true diff --git a/ereport/api/src/lib.rs b/ereport/api/src/lib.rs new file mode 100644 index 00000000000..0c074883d23 --- /dev/null +++ b/ereport/api/src/lib.rs @@ -0,0 +1,117 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! HTTP API for ereport producers. + +use dropshot::HttpError; +use dropshot::HttpResponseOk; +use dropshot::Path; +use dropshot::Query; +use dropshot::RequestContext; +pub use ereport_types::Ena; +pub use ereport_types::Ereport; +pub use ereport_types::EreporterGenerationUuid; +pub use ereport_types::Reporter; +use openapi_manager_types::{ + SupportedVersion, SupportedVersions, api_versions, +}; +use schemars::JsonSchema; +use serde::Deserialize; +use serde::Serialize; +use std::num::NonZeroU32; +use uuid::Uuid; + +api_versions!([ + // WHEN CHANGING THE API (part 1 of 2): + // + // +- Pick a new semver and define it in the list below. The list MUST + // | remain sorted, which generally means that your version should go at + // | the very top. + // | + // | Duplicate this line, uncomment the *second* copy, update that copy for + // | your new API version, and leave the first copy commented out as an + // | example for the next person. + // v + // (next_int, IDENT), + (1, INITIAL), +]); + +// WHEN CHANGING THE API (part 2 of 2): +// +// The call to `api_versions!` above defines constants of type +// `semver::Version` that you can use in your Dropshot API definition to specify +// the version when a particular endpoint was added or removed. For example, if +// you used: +// +// (2, ADD_FOOBAR) +// +// Then you could use `VERSION_ADD_FOOBAR` as the version in which endpoints +// were added or removed. + +/// API for ereport producers. +#[dropshot::api_description] +pub trait Ereporter { + type Context; + + /// Collect a tranche of ereports from this reporter. + #[endpoint { + method = GET, + path = "/ereports/{reporter_id}", + }] + async fn ereports_get( + rqctx: RequestContext, + path: Path, + query: Query, + ) -> Result, HttpError>; +} + +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct ReporterPath { + /// The UUID of the reporter from which to collct ereports. + pub reporter_id: Uuid, +} + +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct EreportQuery { + /// The generation (restart nonce) of the reporter at which all other query + /// parameters are valid. + /// + /// If this value does not match the reporter's current generation, the + /// reporter's response will include the current generation, and will start + /// at the earliest known ENA, rather than the provided `last_seen` ENA.` + pub generation: EreporterGenerationUuid, + + /// If present, the reporter should not include ENAs earlier than this one + /// in its response, provided that the query's requested generation matches + /// the current generation. + pub start_at: Option, + + /// The ENA of the last ereport committed to persistent storage from the + /// requested reporter generation. + /// + /// If the generation parameter matches the reporter's current generation, + /// it is permitted to discard any ereports with ENAs up to and including + /// this value. If the generation has changed from the provided generation, + /// the reporter will not discard data. + pub committed: Option, + + /// Maximum number of ereports to return in this tranche. + pub limit: NonZeroU32, +} + +/// A tranche of ereports received from a reporter. +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct Ereports { + /// The reporter's current generation ID. + /// + /// If this is not equal to the current known generation, then the reporter + /// has restarted. + pub generation: EreporterGenerationUuid, + /// The values of the ereports in this tranche. + pub reports: Vec, + /// If more ereports are present, this value contains the ENA of the ereport + /// immediately after the last report in this tranche. If this is None, no + /// more ereports are currently avaialble. + pub next_page: Option, +} diff --git a/ereport/types/Cargo.toml b/ereport/types/Cargo.toml new file mode 100644 index 00000000000..639c6f3d614 --- /dev/null +++ b/ereport/types/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ereport-types" +version = "0.1.0" +edition = "2024" + +[dependencies] +omicron-uuid-kinds.workspace = true +schemars.workspace = true +serde.workspace = true +serde_json.workspace = true +uuid.workspace = true + +[lints] +workspace = true diff --git a/ereport/types/src/lib.rs b/ereport/types/src/lib.rs new file mode 100644 index 00000000000..4eda8786566 --- /dev/null +++ b/ereport/types/src/lib.rs @@ -0,0 +1,150 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Core types for representing ereports. + +use core::fmt; +pub use omicron_uuid_kinds::EreporterGenerationUuid; +use schemars::JsonSchema; +use serde::Deserialize; +use serde::Serialize; +use uuid::Uuid; + +/// An ereport message. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] +pub struct Ereport { + /// The ENA of the ereport. + pub ena: Ena, + /// The body of the ereport. + pub report: ReportKind, +} + +/// An Error Numeric Association (ENA) +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Serialize, + Deserialize, + JsonSchema, +)] +#[repr(transparent)] +#[serde(transparent)] +pub struct Ena(pub u64); + +impl fmt::Display for Ena { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:#x}", self.0) + } +} + +impl fmt::Debug for Ena { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Ena({:#x})", self.0) + } +} + +impl fmt::UpperHex for Ena { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::UpperHex::fmt(&self.0, f) + } +} + +impl fmt::LowerHex for Ena { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.0, f) + } +} +/// Uniquely identifies the entity that generated an ereport. +#[derive( + Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema, +)] +pub struct Reporter { + pub reporter_id: Uuid, + pub gen_id: EreporterGenerationUuid, +} + +/// The body of an ereport: either an event is reported, or a loss report. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum ReportKind { + /// An ereport. + Event(Event), + /// Ereports were lost, or may have been lost. + Loss { + // The number of ereports that were discarded, if it is known. + /// + /// If ereports are dropped because a buffer has reached its capacity, + /// the reporter is strongly encouraged to attempt to count the number + /// of ereports lost. In other cases, such as a reporter crashing and + /// restarting, the reporter may not be capable of determining the + /// number of ereports that were lost, or even *if* data loss actually + /// occurred. Therefore, a `None` here indicates *possible* data loss, + /// while a `Some(u32)` indicates *known* data loss. + lost: Option, + }, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] +pub struct Event { + pub class: String, + pub data: serde_json::Value, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_roundtrip() { + let ereport = Ereport { + reporter: Reporter { + reporter_id: Uuid::new_v4(), + gen_id: EreporterGenerationUuid::new_v4(), + }, + ena: Ena(0x3cae76440c100001), + report: ReportKind::Event(Event { + // Example ereport taken from https://rfd.shared.oxide.computer/rfd/0520#_ereports_in_the_fma + class: "ereport.cpu.generic-x86.cache".to_string(), + data: serde_json::json!({ + "version": 0x0, + "class": "list.suspect", + "uuid": "0348743e-0600-4c77-b7ea-6eda191536e4", + "code": "FMD-8000-0W", + "diag-time": "1705014884 472900", + "de": { + "version": 0x0, + "scheme": "fmd", + "authority": { + "version": 0x0, + "product-id": "oxide", + "server-id": "BRM42220016", + }, + "mod-name": "fmd-self-diagnosis", + "mod-version": "1.0", + }, + "fault-list": [ + { + "version": 0x0, + "class": "defect.sunos.fmd.nosub", + "certainty": 0x64, + "nosub_class": "ereport.cpu.generic-x86.cache", + } + ], + "fault-status": 0x1, + "severity": "minor", + }), + }), + }; + let ereport_string = serde_json::to_string_pretty(&ereport) + .expect("ereport should serialize"); + eprintln!("JSON: {ereport_string}"); + let deserialized = dbg!(serde_json::from_str(&ereport_string)) + .expect("ereport should deserialize"); + assert_eq!(ereport, deserialized) + } +} diff --git a/uuid-kinds/src/lib.rs b/uuid-kinds/src/lib.rs index 0d66b230c84..cd5821293a5 100644 --- a/uuid-kinds/src/lib.rs +++ b/uuid-kinds/src/lib.rs @@ -59,6 +59,7 @@ impl_typed_uuid_kind! { DemoSaga => "demo_saga", Downstairs => "downstairs", DownstairsRegion => "downstairs_region", + EreporterGeneration => "ereporter_generation", ExternalIp => "external_ip", Instance => "instance", LoopbackAddress => "loopback_address", From 451dd1ea49e591c2c31b1012028ef9522634f1f6 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 12:30:09 -0700 Subject: [PATCH 02/18] Cargo.toml seating arrangements --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 969fe89816e..2590cf95051 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ members = [ "dns-server", "dns-server-api", "end-to-end-tests", + "ereport/api", "ereport/types", "gateway", "gateway-api", @@ -132,7 +133,7 @@ members = [ "wicketd", "wicketd-api", "workspace-hack", - "zone-setup", "ereport/api", + "zone-setup", ] default-members = [ @@ -188,6 +189,7 @@ default-members = [ "dns-server", "dns-server-api", "end-to-end-tests", + "ereport/api", "ereport/types", "gateway", "gateway-api", From 24867451133ee6a08cedf199b2a531128c3ed073 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 12:31:56 -0700 Subject: [PATCH 03/18] oh right i removed that part --- ereport/types/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ereport/types/src/lib.rs b/ereport/types/src/lib.rs index 4eda8786566..2e6aaa8f745 100644 --- a/ereport/types/src/lib.rs +++ b/ereport/types/src/lib.rs @@ -102,10 +102,6 @@ mod tests { #[test] fn test_roundtrip() { let ereport = Ereport { - reporter: Reporter { - reporter_id: Uuid::new_v4(), - gen_id: EreporterGenerationUuid::new_v4(), - }, ena: Ena(0x3cae76440c100001), report: ReportKind::Event(Event { // Example ereport taken from https://rfd.shared.oxide.computer/rfd/0520#_ereports_in_the_fma From e542817525bbe5b0b069397f368184fb0ce28b77 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 12:32:16 -0700 Subject: [PATCH 04/18] api_versions! macro requires you depend on semver --- Cargo.lock | 1 + ereport/api/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index af7fbcfee60..00afd371b8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3053,6 +3053,7 @@ dependencies = [ "ereport-types", "openapi-manager-types", "schemars", + "semver 1.0.25", "serde", "serde_json", "thiserror 1.0.69", diff --git a/ereport/api/Cargo.toml b/ereport/api/Cargo.toml index 648648581d9..ec6fba87bb9 100644 --- a/ereport/api/Cargo.toml +++ b/ereport/api/Cargo.toml @@ -8,6 +8,7 @@ ereport-types.workspace = true dropshot.workspace = true openapi-manager-types.workspace = true schemars.workspace = true +semver.workspace = true serde.workspace = true serde_json.workspace = true thiserror.workspace = true From 992c6d4fe338f207575a8a2a30a806fe09b78c8e Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 13:17:51 -0700 Subject: [PATCH 05/18] workspace hack --- Cargo.lock | 2 ++ ereport/api/Cargo.toml | 1 + ereport/types/Cargo.toml | 1 + 3 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 00afd371b8d..9ed5cf6ece2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3039,6 +3039,7 @@ name = "ereport-types" version = "0.1.0" dependencies = [ "omicron-uuid-kinds", + "omicron-workspace-hack", "schemars", "serde", "serde_json", @@ -3051,6 +3052,7 @@ version = "0.1.0" dependencies = [ "dropshot 0.16.0", "ereport-types", + "omicron-workspace-hack", "openapi-manager-types", "schemars", "semver 1.0.25", diff --git a/ereport/api/Cargo.toml b/ereport/api/Cargo.toml index ec6fba87bb9..872e7be5a7b 100644 --- a/ereport/api/Cargo.toml +++ b/ereport/api/Cargo.toml @@ -13,6 +13,7 @@ serde.workspace = true serde_json.workspace = true thiserror.workspace = true uuid.workspace = true +omicron-workspace-hack.workspace = true [lints] workspace = true diff --git a/ereport/types/Cargo.toml b/ereport/types/Cargo.toml index 639c6f3d614..cd1bb0d812f 100644 --- a/ereport/types/Cargo.toml +++ b/ereport/types/Cargo.toml @@ -9,6 +9,7 @@ schemars.workspace = true serde.workspace = true serde_json.workspace = true uuid.workspace = true +omicron-workspace-hack.workspace = true [lints] workspace = true From 0c2a0bcc4a63e1c18d72a3e264a5f418b0c3fffb Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 14:16:33 -0700 Subject: [PATCH 06/18] actually generate the api --- Cargo.lock | 1 + Cargo.toml | 1 + dev-tools/openapi-manager/Cargo.toml | 1 + dev-tools/openapi-manager/src/omicron.rs | 12 + ereport/api/src/lib.rs | 2 +- openapi/ereporter/ereporter-1.0.0-e4bfb2.json | 240 ++++++++++++++++++ openapi/ereporter/ereporter-latest.json | 1 + 7 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 openapi/ereporter/ereporter-1.0.0-e4bfb2.json create mode 120000 openapi/ereporter/ereporter-latest.json diff --git a/Cargo.lock b/Cargo.lock index 9ed5cf6ece2..aedd890bdb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7770,6 +7770,7 @@ dependencies = [ "debug-ignore", "dns-server-api", "dropshot 0.16.0", + "ereporter-api", "fs-err", "gateway-api", "hex", diff --git a/Cargo.toml b/Cargo.toml index 2590cf95051..a9b6b2662cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -389,6 +389,7 @@ dpd-client = { path = "clients/dpd-client" } dropshot = { version = "0.16.0", features = [ "usdt-probes" ] } dyn-clone = "1.0.19" either = "1.14.0" +ereporter-api = { path = "ereport/api" } ereport-types = { path = "ereport/types" } expectorate = "1.1.0" fatfs = "0.3.6" diff --git a/dev-tools/openapi-manager/Cargo.toml b/dev-tools/openapi-manager/Cargo.toml index fc9048412fc..4dea84a0ea8 100644 --- a/dev-tools/openapi-manager/Cargo.toml +++ b/dev-tools/openapi-manager/Cargo.toml @@ -18,6 +18,7 @@ cockroach-admin-api.workspace = true debug-ignore.workspace = true dns-server-api.workspace = true dropshot.workspace = true +ereporter-api.workspace = true hex.workspace = true fs-err.workspace = true gateway-api.workspace = true diff --git a/dev-tools/openapi-manager/src/omicron.rs b/dev-tools/openapi-manager/src/omicron.rs index 7d9b3bc67fa..c20f8739702 100644 --- a/dev-tools/openapi-manager/src/omicron.rs +++ b/dev-tools/openapi-manager/src/omicron.rs @@ -84,6 +84,18 @@ pub fn all_apis() -> Vec { dns_server_api::dns_server_api_mod::stub_api_description, ident: "dns-server", extra_validation: None, + }, + ManagedApiConfig { + title: "Ereporter API", + versions: Versions::new_versioned( + ereporter_api::supported_versions() + ), + description: "API for ereport producers", + boundary: ApiBoundary::Internal, + api_description: + ereporter_api::ereporter_api_mod::stub_api_description, + ident: "ereporter", + extra_validation: None, }, ManagedApiConfig { title: "Installinator API", diff --git a/ereport/api/src/lib.rs b/ereport/api/src/lib.rs index 0c074883d23..aed4d8493cc 100644 --- a/ereport/api/src/lib.rs +++ b/ereport/api/src/lib.rs @@ -51,7 +51,7 @@ api_versions!([ /// API for ereport producers. #[dropshot::api_description] -pub trait Ereporter { +pub trait EreporterApi { type Context; /// Collect a tranche of ereports from this reporter. diff --git a/openapi/ereporter/ereporter-1.0.0-e4bfb2.json b/openapi/ereporter/ereporter-1.0.0-e4bfb2.json new file mode 100644 index 00000000000..ac057990879 --- /dev/null +++ b/openapi/ereporter/ereporter-1.0.0-e4bfb2.json @@ -0,0 +1,240 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Ereporter API", + "description": "API for ereport producers", + "contact": { + "url": "https://oxide.computer", + "email": "api@oxide.computer" + }, + "version": "1.0.0" + }, + "paths": { + "/ereports/{reporter_id}": { + "get": { + "summary": "Collect a tranche of ereports from this reporter.", + "operationId": "ereports_get", + "parameters": [ + { + "in": "path", + "name": "reporter_id", + "description": "The UUID of the reporter from which to collct ereports.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "in": "query", + "name": "committed", + "description": "The ENA of the last ereport committed to persistent storage from the requested reporter generation.\n\nIf the generation parameter matches the reporter's current generation, it is permitted to discard any ereports with ENAs up to and including this value. If the generation has changed from the provided generation, the reporter will not discard data.", + "schema": { + "nullable": true, + "type": "integer", + "format": "uint64", + "minimum": 0 + } + }, + { + "in": "query", + "name": "generation", + "description": "The generation (restart nonce) of the reporter at which all other query parameters are valid.\n\nIf this value does not match the reporter's current generation, the reporter's response will include the current generation, and will start at the earliest known ENA, rather than the provided `last_seen` ENA.`", + "required": true, + "schema": { + "$ref": "#/components/schemas/TypedUuidForEreporterGenerationKind" + } + }, + { + "in": "query", + "name": "limit", + "description": "Maximum number of ereports to return in this tranche.", + "required": true, + "schema": { + "type": "integer", + "format": "uint32", + "minimum": 1 + } + }, + { + "in": "query", + "name": "start_at", + "description": "If present, the reporter should not include ENAs earlier than this one in its response, provided that the query's requested generation matches the current generation.", + "schema": { + "nullable": true, + "type": "integer", + "format": "uint64", + "minimum": 0 + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Ereports" + } + } + } + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + } + } + }, + "components": { + "schemas": { + "Ereport": { + "description": "An ereport message.", + "type": "object", + "properties": { + "ena": { + "description": "The ENA of the ereport.", + "type": "integer", + "format": "uint64", + "minimum": 0 + }, + "report": { + "description": "The body of the ereport.", + "allOf": [ + { + "$ref": "#/components/schemas/ReportKind" + } + ] + } + }, + "required": [ + "ena", + "report" + ] + }, + "Ereports": { + "description": "A tranche of ereports received from a reporter.", + "type": "object", + "properties": { + "generation": { + "description": "The reporter's current generation ID.\n\nIf this is not equal to the current known generation, then the reporter has restarted.", + "allOf": [ + { + "$ref": "#/components/schemas/TypedUuidForEreporterGenerationKind" + } + ] + }, + "next_page": { + "nullable": true, + "description": "If more ereports are present, this value contains the ENA of the ereport immediately after the last report in this tranche. If this is None, no more ereports are currently avaialble.", + "type": "integer", + "format": "uint64", + "minimum": 0 + }, + "reports": { + "description": "The values of the ereports in this tranche.", + "type": "array", + "items": { + "$ref": "#/components/schemas/Ereport" + } + } + }, + "required": [ + "generation", + "reports" + ] + }, + "Error": { + "description": "Error information from a response.", + "type": "object", + "properties": { + "error_code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "request_id": { + "type": "string" + } + }, + "required": [ + "message", + "request_id" + ] + }, + "Event": { + "type": "object", + "properties": { + "class": { + "type": "string" + }, + "data": {} + }, + "required": [ + "class", + "data" + ] + }, + "ReportKind": { + "description": "The body of an ereport: either an event is reported, or a loss report.", + "oneOf": [ + { + "description": "An ereport.", + "type": "object", + "properties": { + "event": { + "$ref": "#/components/schemas/Event" + } + }, + "required": [ + "event" + ], + "additionalProperties": false + }, + { + "description": "Ereports were lost, or may have been lost.", + "type": "object", + "properties": { + "loss": { + "type": "object", + "properties": { + "lost": { + "nullable": true, + "description": "If ereports are dropped because a buffer has reached its capacity, the reporter is strongly encouraged to attempt to count the number of ereports lost. In other cases, such as a reporter crashing and restarting, the reporter may not be capable of determining the number of ereports that were lost, or even *if* data loss actually occurred. Therefore, a `None` here indicates *possible* data loss, while a `Some(u32)` indicates *known* data loss.", + "type": "integer", + "format": "uint32", + "minimum": 0 + } + } + } + }, + "required": [ + "loss" + ], + "additionalProperties": false + } + ] + }, + "TypedUuidForEreporterGenerationKind": { + "type": "string", + "format": "uuid" + } + }, + "responses": { + "Error": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } +} diff --git a/openapi/ereporter/ereporter-latest.json b/openapi/ereporter/ereporter-latest.json new file mode 120000 index 00000000000..3989fd8be89 --- /dev/null +++ b/openapi/ereporter/ereporter-latest.json @@ -0,0 +1 @@ +ereporter-1.0.0-e4bfb2.json \ No newline at end of file From e72858e3aaade10ac12af27f081d2d959d9f268e Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 15:46:31 -0700 Subject: [PATCH 07/18] add client --- Cargo.lock | 18 ++++++++++++++++++ Cargo.toml | 2 ++ clients/ereporter-client/Cargo.toml | 21 +++++++++++++++++++++ clients/ereporter-client/src/lib.rs | 26 ++++++++++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 clients/ereporter-client/Cargo.toml create mode 100644 clients/ereporter-client/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index aedd890bdb7..28b0bde21b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3062,6 +3062,24 @@ dependencies = [ "uuid", ] +[[package]] +name = "ereporter-client" +version = "0.1.0" +dependencies = [ + "chrono", + "ereport-types", + "expectorate", + "http", + "omicron-uuid-kinds", + "omicron-workspace-hack", + "progenitor 0.9.1", + "reqwest", + "schemars", + "serde", + "slog", + "uuid", +] + [[package]] name = "errno" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index a9b6b2662cc..057713ae988 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ "clients/ddm-admin-client", "clients/dns-service-client", "clients/dpd-client", + "clients/ereporter-client", "clients/gateway-client", "clients/installinator-client", "clients/nexus-client", @@ -152,6 +153,7 @@ default-members = [ "clients/ddm-admin-client", "clients/dns-service-client", "clients/dpd-client", + "clients/ereporter-client", "clients/gateway-client", "clients/installinator-client", "clients/nexus-client", diff --git a/clients/ereporter-client/Cargo.toml b/clients/ereporter-client/Cargo.toml new file mode 100644 index 00000000000..3d0ef4d1f6a --- /dev/null +++ b/clients/ereporter-client/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ereporter-client" +version = "0.1.0" +edition = "2024" + +[lints] +workspace = true + +[dependencies] +chrono.workspace = true +expectorate.workspace = true +ereport-types.workspace = true +http.workspace = true +progenitor.workspace = true +reqwest = { workspace = true, features = ["json", "rustls-tls", "stream"] } +schemars.workspace = true +serde.workspace = true +slog.workspace = true +omicron-uuid-kinds.workspace = true +omicron-workspace-hack.workspace = true +uuid.workspace = true diff --git a/clients/ereporter-client/src/lib.rs b/clients/ereporter-client/src/lib.rs new file mode 100644 index 00000000000..3dfc1024a1c --- /dev/null +++ b/clients/ereporter-client/src/lib.rs @@ -0,0 +1,26 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +progenitor::generate_api!( + spec = "../../openapi/ereporter/ereporter-latest.json", + inner_type = slog::Logger, + derives = [schemars::JsonSchema, Clone, Eq, PartialEq], + pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { + slog::debug!(log, "client request"; + "method" => %request.method(), + "uri" => %request.url(), + "body" => ?&request.body(), + ); + }), + post_hook = (|log: &slog::Logger, result: &Result<_, _>| { + slog::debug!(log, "client response"; "result" => ?result); + }), + replace = { + Ena = ereport_types::Ena, + Ereport = ereport_types::Ereport, + Event = ereport_types::Event, + ReportKind = ereport_types::ReportKind, + TypedUuidForEreporterGenerationKind = omicron_uuid_kinds::EreporterGenerationUuid, + } +); From 1c01fbd4bd4caa7fe97b92dcb2eb3b3edb83e574 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 15:48:38 -0700 Subject: [PATCH 08/18] actually i DO want ENAs newtyped... --- ereport/types/src/lib.rs | 1 - ...4bfb2.json => ereporter-1.0.0-60871e.json} | 32 +++++++++++-------- openapi/ereporter/ereporter-latest.json | 2 +- 3 files changed, 19 insertions(+), 16 deletions(-) rename openapi/ereporter/{ereporter-1.0.0-e4bfb2.json => ereporter-1.0.0-60871e.json} (93%) diff --git a/ereport/types/src/lib.rs b/ereport/types/src/lib.rs index 2e6aaa8f745..7a9c4a1bb3d 100644 --- a/ereport/types/src/lib.rs +++ b/ereport/types/src/lib.rs @@ -33,7 +33,6 @@ pub struct Ereport { JsonSchema, )] #[repr(transparent)] -#[serde(transparent)] pub struct Ena(pub u64); impl fmt::Display for Ena { diff --git a/openapi/ereporter/ereporter-1.0.0-e4bfb2.json b/openapi/ereporter/ereporter-1.0.0-60871e.json similarity index 93% rename from openapi/ereporter/ereporter-1.0.0-e4bfb2.json rename to openapi/ereporter/ereporter-1.0.0-60871e.json index ac057990879..4ea1e5afb87 100644 --- a/openapi/ereporter/ereporter-1.0.0-e4bfb2.json +++ b/openapi/ereporter/ereporter-1.0.0-60871e.json @@ -30,10 +30,7 @@ "name": "committed", "description": "The ENA of the last ereport committed to persistent storage from the requested reporter generation.\n\nIf the generation parameter matches the reporter's current generation, it is permitted to discard any ereports with ENAs up to and including this value. If the generation has changed from the provided generation, the reporter will not discard data.", "schema": { - "nullable": true, - "type": "integer", - "format": "uint64", - "minimum": 0 + "$ref": "#/components/schemas/Ena" } }, { @@ -61,10 +58,7 @@ "name": "start_at", "description": "If present, the reporter should not include ENAs earlier than this one in its response, provided that the query's requested generation matches the current generation.", "schema": { - "nullable": true, - "type": "integer", - "format": "uint64", - "minimum": 0 + "$ref": "#/components/schemas/Ena" } } ], @@ -91,15 +85,23 @@ }, "components": { "schemas": { + "Ena": { + "description": "An Error Numeric Association (ENA)", + "type": "integer", + "format": "uint64", + "minimum": 0 + }, "Ereport": { "description": "An ereport message.", "type": "object", "properties": { "ena": { "description": "The ENA of the ereport.", - "type": "integer", - "format": "uint64", - "minimum": 0 + "allOf": [ + { + "$ref": "#/components/schemas/Ena" + } + ] }, "report": { "description": "The body of the ereport.", @@ -130,9 +132,11 @@ "next_page": { "nullable": true, "description": "If more ereports are present, this value contains the ENA of the ereport immediately after the last report in this tranche. If this is None, no more ereports are currently avaialble.", - "type": "integer", - "format": "uint64", - "minimum": 0 + "allOf": [ + { + "$ref": "#/components/schemas/Ena" + } + ] }, "reports": { "description": "The values of the ereports in this tranche.", diff --git a/openapi/ereporter/ereporter-latest.json b/openapi/ereporter/ereporter-latest.json index 3989fd8be89..99e90e81b7e 120000 --- a/openapi/ereporter/ereporter-latest.json +++ b/openapi/ereporter/ereporter-latest.json @@ -1 +1 @@ -ereporter-1.0.0-e4bfb2.json \ No newline at end of file +ereporter-1.0.0-60871e.json \ No newline at end of file From 683e9835735ada7ec5ea704c67801cbdcceaba0d Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 16:22:15 -0700 Subject: [PATCH 09/18] add to ls-apis and add (currently unused) deps --- Cargo.lock | 2 ++ Cargo.toml | 1 + dev-tools/ls-apis/api-manifest.toml | 12 ++++++++++++ nexus/Cargo.toml | 1 + sled-agent/Cargo.toml | 1 + 5 files changed, 17 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 28b0bde21b4..b6d6f7ddd8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7082,6 +7082,7 @@ dependencies = [ "dns-service-client", "dpd-client", "dropshot 0.16.0", + "ereporter-client", "expectorate", "fatfs", "futures", @@ -7426,6 +7427,7 @@ dependencies = [ "dns-service-client", "dpd-client", "dropshot 0.16.0", + "ereporter-api", "expectorate", "flate2", "flume", diff --git a/Cargo.toml b/Cargo.toml index 057713ae988..6c9ccd561a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -392,6 +392,7 @@ dropshot = { version = "0.16.0", features = [ "usdt-probes" ] } dyn-clone = "1.0.19" either = "1.14.0" ereporter-api = { path = "ereport/api" } +ereporter-client = { path = "clients/ereporter-client" } ereport-types = { path = "ereport/types" } expectorate = "1.1.0" fatfs = "0.3.6" diff --git a/dev-tools/ls-apis/api-manifest.toml b/dev-tools/ls-apis/api-manifest.toml index d865b6e1155..7e5d0445af7 100644 --- a/dev-tools/ls-apis/api-manifest.toml +++ b/dev-tools/ls-apis/api-manifest.toml @@ -270,6 +270,18 @@ and exists as a client library within omicron. This is because the Dendrite \ repo is not currently open source. """ +[[apis]] +client_package_name = "ereporter-client" +label = "Ereporter" +server_package_name = "ereporter-api" +versioned_how = "server" +notes = """ +Implemented by sled-agents and by MGS, and consumed by Nexus to collect \ +ereports. + +The sled-agent and MGS APIs are server-versioned, so this can be as well. +""" + [[apis]] client_package_name = "lldpd-client" label = "LLDP daemon" diff --git a/nexus/Cargo.toml b/nexus/Cargo.toml index afbbc793193..14e731fb5e4 100644 --- a/nexus/Cargo.toml +++ b/nexus/Cargo.toml @@ -31,6 +31,7 @@ crucible-pantry-client.workspace = true crucible-common.workspace = true dns-service-client.workspace = true dpd-client.workspace = true +ereporter-client.workspace = true mg-admin-client.workspace = true dropshot.workspace = true fatfs.workspace = true diff --git a/sled-agent/Cargo.toml b/sled-agent/Cargo.toml index b8ce58c6cb7..3f2a5275c85 100644 --- a/sled-agent/Cargo.toml +++ b/sled-agent/Cargo.toml @@ -31,6 +31,7 @@ dns-service-client.workspace = true dpd-client.workspace = true display-error-chain.workspace = true dropshot.workspace = true +ereporter-api.workspace = true flate2.workspace = true flume.workspace = true futures.workspace = true From f42577cb8d3b4140c39218d35e42e53f209da3c3 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 19 Mar 2025 16:43:02 -0700 Subject: [PATCH 10/18] gateway should also expose ereporter-api --- Cargo.lock | 1 + gateway/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index b6d6f7ddd8b..06223c2108f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6962,6 +6962,7 @@ dependencies = [ "chrono", "clap", "dropshot 0.16.0", + "ereporter-api", "expectorate", "futures", "gateway-api", diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index e754daf1855..3ad46da22b4 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -14,6 +14,7 @@ camino.workspace = true chrono.workspace = true clap.workspace = true dropshot.workspace = true +ereporter-api.workspace = true futures.workspace = true gateway-api.workspace = true gateway-messages.workspace = true From ab921b7c60e3f07d5a22a67fffed76f47230615b Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 21 Mar 2025 13:49:59 -0700 Subject: [PATCH 11/18] Update dev-tools/openapi-manager/src/omicron.rs Co-authored-by: David Pacheco --- dev-tools/openapi-manager/src/omicron.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-tools/openapi-manager/src/omicron.rs b/dev-tools/openapi-manager/src/omicron.rs index c20f8739702..7179c328a29 100644 --- a/dev-tools/openapi-manager/src/omicron.rs +++ b/dev-tools/openapi-manager/src/omicron.rs @@ -85,7 +85,7 @@ pub fn all_apis() -> Vec { ident: "dns-server", extra_validation: None, }, - ManagedApiConfig { + ManagedApiConfig { title: "Ereporter API", versions: Versions::new_versioned( ereporter_api::supported_versions() From 48e14ecc232e9e49bdf1e03723963bd48050cb09 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 21 Mar 2025 14:01:59 -0700 Subject: [PATCH 12/18] remove most of the replace directives --- clients/ereporter-client/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/clients/ereporter-client/src/lib.rs b/clients/ereporter-client/src/lib.rs index 3dfc1024a1c..9c3e625637c 100644 --- a/clients/ereporter-client/src/lib.rs +++ b/clients/ereporter-client/src/lib.rs @@ -18,9 +18,6 @@ progenitor::generate_api!( }), replace = { Ena = ereport_types::Ena, - Ereport = ereport_types::Ereport, - Event = ereport_types::Event, - ReportKind = ereport_types::ReportKind, TypedUuidForEreporterGenerationKind = omicron_uuid_kinds::EreporterGenerationUuid, } ); From f75b9d4f54c195004c1b0cffbee3f23c953c4005 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 21 Mar 2025 14:23:26 -0700 Subject: [PATCH 13/18] address @davepacheco's suggestions --- ereport/api/src/lib.rs | 17 +++++++------ ...0871e.json => ereporter-1.0.0-48da02.json} | 24 ++++++++----------- openapi/ereporter/ereporter-latest.json | 2 +- 3 files changed, 19 insertions(+), 24 deletions(-) rename openapi/ereporter/{ereporter-1.0.0-60871e.json => ereporter-1.0.0-48da02.json} (93%) diff --git a/ereport/api/src/lib.rs b/ereport/api/src/lib.rs index aed4d8493cc..4e687bab813 100644 --- a/ereport/api/src/lib.rs +++ b/ereport/api/src/lib.rs @@ -9,6 +9,7 @@ use dropshot::HttpResponseOk; use dropshot::Path; use dropshot::Query; use dropshot::RequestContext; +use dropshot::ResultsPage; pub use ereport_types::Ena; pub use ereport_types::Ereport; pub use ereport_types::EreporterGenerationUuid; @@ -56,10 +57,10 @@ pub trait EreporterApi { /// Collect a tranche of ereports from this reporter. #[endpoint { - method = GET, + method = POST, path = "/ereports/{reporter_id}", }] - async fn ereports_get( + async fn ereports_collect( rqctx: RequestContext, path: Path, query: Query, @@ -101,17 +102,15 @@ pub struct EreportQuery { } /// A tranche of ereports received from a reporter. -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct Ereports { /// The reporter's current generation ID. /// /// If this is not equal to the current known generation, then the reporter /// has restarted. pub generation: EreporterGenerationUuid, - /// The values of the ereports in this tranche. - pub reports: Vec, - /// If more ereports are present, this value contains the ENA of the ereport - /// immediately after the last report in this tranche. If this is None, no - /// more ereports are currently avaialble. - pub next_page: Option, + /// The ereports in this tranche, and the ENA of the next apge of ereports + /// (if one exists).) + #[serde(flatten)] + pub reports: ResultsPage, } diff --git a/openapi/ereporter/ereporter-1.0.0-60871e.json b/openapi/ereporter/ereporter-1.0.0-48da02.json similarity index 93% rename from openapi/ereporter/ereporter-1.0.0-60871e.json rename to openapi/ereporter/ereporter-1.0.0-48da02.json index 4ea1e5afb87..9bbf2210569 100644 --- a/openapi/ereporter/ereporter-1.0.0-60871e.json +++ b/openapi/ereporter/ereporter-1.0.0-48da02.json @@ -11,9 +11,9 @@ }, "paths": { "/ereports/{reporter_id}": { - "get": { + "post": { "summary": "Collect a tranche of ereports from this reporter.", - "operationId": "ereports_get", + "operationId": "ereports_collect", "parameters": [ { "in": "path", @@ -129,26 +129,22 @@ } ] }, - "next_page": { - "nullable": true, - "description": "If more ereports are present, this value contains the ENA of the ereport immediately after the last report in this tranche. If this is None, no more ereports are currently avaialble.", - "allOf": [ - { - "$ref": "#/components/schemas/Ena" - } - ] - }, - "reports": { - "description": "The values of the ereports in this tranche.", + "items": { + "description": "list of items on this page of results", "type": "array", "items": { "$ref": "#/components/schemas/Ereport" } + }, + "next_page": { + "nullable": true, + "description": "token used to fetch the next page of results (if any)", + "type": "string" } }, "required": [ "generation", - "reports" + "items" ] }, "Error": { diff --git a/openapi/ereporter/ereporter-latest.json b/openapi/ereporter/ereporter-latest.json index 99e90e81b7e..9f1ec69b92b 120000 --- a/openapi/ereporter/ereporter-latest.json +++ b/openapi/ereporter/ereporter-latest.json @@ -1 +1 @@ -ereporter-1.0.0-60871e.json \ No newline at end of file +ereporter-1.0.0-48da02.json \ No newline at end of file From 3febae613bccf9d84a2d6e2be673d6ba7c224a46 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 21 Mar 2025 14:32:33 -0700 Subject: [PATCH 14/18] add missing import --- Cargo.lock | 1 + clients/ereporter-client/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 06223c2108f..95fca6144ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3076,6 +3076,7 @@ dependencies = [ "reqwest", "schemars", "serde", + "serde_json", "slog", "uuid", ] diff --git a/clients/ereporter-client/Cargo.toml b/clients/ereporter-client/Cargo.toml index 3d0ef4d1f6a..acc5abaa4f8 100644 --- a/clients/ereporter-client/Cargo.toml +++ b/clients/ereporter-client/Cargo.toml @@ -15,6 +15,7 @@ progenitor.workspace = true reqwest = { workspace = true, features = ["json", "rustls-tls", "stream"] } schemars.workspace = true serde.workspace = true +serde_json.workspace = true slog.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true From cb1d89c82027cfd3401fe8b9514042ecc3b69044 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 24 Mar 2025 09:21:24 -0700 Subject: [PATCH 15/18] update ls-apis output --- dev-tools/ls-apis/tests/api_dependencies.out | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev-tools/ls-apis/tests/api_dependencies.out b/dev-tools/ls-apis/tests/api_dependencies.out index ed35331ce3e..c7ebe0ce3ba 100644 --- a/dev-tools/ls-apis/tests/api_dependencies.out +++ b/dev-tools/ls-apis/tests/api_dependencies.out @@ -42,6 +42,9 @@ Dendrite DPD (client: dpd-client) Downstairs Controller (debugging only) (client: dsc-client) +Ereporter (client: ereporter-client) + consumed by: omicron-nexus (omicron/nexus) via 1 path + Management Gateway Service (client: gateway-client) consumed by: dpd (dendrite/dpd) via 1 path consumed by: omicron-nexus (omicron/nexus) via 3 paths From b8f9d50b9dae951477f5f7ca0a98feb7b723dfbc Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 24 Mar 2025 12:33:19 -0700 Subject: [PATCH 16/18] typo fix from @andrewjstone Co-authored-by: Andrew J. Stone --- ereport/api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereport/api/src/lib.rs b/ereport/api/src/lib.rs index 4e687bab813..1cfbd949a1c 100644 --- a/ereport/api/src/lib.rs +++ b/ereport/api/src/lib.rs @@ -109,7 +109,7 @@ pub struct Ereports { /// If this is not equal to the current known generation, then the reporter /// has restarted. pub generation: EreporterGenerationUuid, - /// The ereports in this tranche, and the ENA of the next apge of ereports + /// The ereports in this tranche, and the ENA of the next page of ereports /// (if one exists).) #[serde(flatten)] pub reports: ResultsPage, From 3c5eb138f41aa44b1f67c38260ce380c5b57dd31 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 24 Mar 2025 15:44:29 -0700 Subject: [PATCH 17/18] replace option with an enum --- ereport/types/src/lib.rs | 31 ++++++----- ...8da02.json => ereporter-1.0.0-e64494.json} | 52 +++++++++++++++---- openapi/ereporter/ereporter-latest.json | 2 +- 3 files changed, 62 insertions(+), 23 deletions(-) rename openapi/ereporter/{ereporter-1.0.0-48da02.json => ereporter-1.0.0-e64494.json} (81%) diff --git a/ereport/types/src/lib.rs b/ereport/types/src/lib.rs index 7a9c4a1bb3d..2835f48248f 100644 --- a/ereport/types/src/lib.rs +++ b/ereport/types/src/lib.rs @@ -74,18 +74,25 @@ pub enum ReportKind { /// An ereport. Event(Event), /// Ereports were lost, or may have been lost. - Loss { - // The number of ereports that were discarded, if it is known. - /// - /// If ereports are dropped because a buffer has reached its capacity, - /// the reporter is strongly encouraged to attempt to count the number - /// of ereports lost. In other cases, such as a reporter crashing and - /// restarting, the reporter may not be capable of determining the - /// number of ereports that were lost, or even *if* data loss actually - /// occurred. Therefore, a `None` here indicates *possible* data loss, - /// while a `Some(u32)` indicates *known* data loss. - lost: Option, - }, + Loss(LossReport), +} + +/// The number of ereports that were discarded, if it is known. +/// +/// If ereports are dropped because a buffer has reached its capacity, +/// the reporter is strongly encouraged to attempt to count the number +/// of ereports lost. In other cases, such as a reporter crashing and +/// restarting, the reporter may not be capable of determining the +/// number of ereports that were lost, or even *if* data loss actually +/// occurred. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +#[serde(tag = "type", content = "lost")] +pub enum LossReport { + /// An unknown number of ereports MAY have been lost. + Unknown, + /// The provided number of ereports are known to have been lost. + Exact(u32), } #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)] diff --git a/openapi/ereporter/ereporter-1.0.0-48da02.json b/openapi/ereporter/ereporter-1.0.0-e64494.json similarity index 81% rename from openapi/ereporter/ereporter-1.0.0-48da02.json rename to openapi/ereporter/ereporter-1.0.0-e64494.json index 9bbf2210569..d3c641ae624 100644 --- a/openapi/ereporter/ereporter-1.0.0-48da02.json +++ b/openapi/ereporter/ereporter-1.0.0-e64494.json @@ -179,6 +179,47 @@ "data" ] }, + "LossReport": { + "description": "The number of ereports that were discarded, if it is known.\n\nIf ereports are dropped because a buffer has reached its capacity, the reporter is strongly encouraged to attempt to count the number of ereports lost. In other cases, such as a reporter crashing and restarting, the reporter may not be capable of determining the number of ereports that were lost, or even *if* data loss actually occurred.", + "oneOf": [ + { + "description": "An unknown number of ereports MAY have been lost.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "unknown" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "The provided number of ereports are known to have been lost.", + "type": "object", + "properties": { + "lost": { + "type": "integer", + "format": "uint32", + "minimum": 0 + }, + "type": { + "type": "string", + "enum": [ + "exact" + ] + } + }, + "required": [ + "lost", + "type" + ] + } + ] + }, "ReportKind": { "description": "The body of an ereport: either an event is reported, or a loss report.", "oneOf": [ @@ -200,16 +241,7 @@ "type": "object", "properties": { "loss": { - "type": "object", - "properties": { - "lost": { - "nullable": true, - "description": "If ereports are dropped because a buffer has reached its capacity, the reporter is strongly encouraged to attempt to count the number of ereports lost. In other cases, such as a reporter crashing and restarting, the reporter may not be capable of determining the number of ereports that were lost, or even *if* data loss actually occurred. Therefore, a `None` here indicates *possible* data loss, while a `Some(u32)` indicates *known* data loss.", - "type": "integer", - "format": "uint32", - "minimum": 0 - } - } + "$ref": "#/components/schemas/LossReport" } }, "required": [ diff --git a/openapi/ereporter/ereporter-latest.json b/openapi/ereporter/ereporter-latest.json index 9f1ec69b92b..14f13401191 120000 --- a/openapi/ereporter/ereporter-latest.json +++ b/openapi/ereporter/ereporter-latest.json @@ -1 +1 @@ -ereporter-1.0.0-48da02.json \ No newline at end of file +ereporter-1.0.0-e64494.json \ No newline at end of file From b70751d98c98338cde209e6ab518e9005834d3dd Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 25 Mar 2025 14:05:21 -0700 Subject: [PATCH 18/18] s/ereporter/ereport --- Cargo.lock | 36 +++++++++---------- Cargo.toml | 8 ++--- .../Cargo.toml | 2 +- .../src/lib.rs | 2 +- dev-tools/ls-apis/api-manifest.toml | 6 ++-- dev-tools/openapi-manager/Cargo.toml | 2 +- dev-tools/openapi-manager/src/omicron.rs | 8 ++--- ereport/api/Cargo.toml | 2 +- ereport/api/src/lib.rs | 4 +-- gateway/Cargo.toml | 2 +- nexus/Cargo.toml | 2 +- .../ereport-1.0.0-e41934.json} | 4 +-- openapi/ereport/ereport-latest.json | 1 + openapi/ereporter/ereporter-latest.json | 1 - sled-agent/Cargo.toml | 2 +- 15 files changed, 41 insertions(+), 41 deletions(-) rename clients/{ereporter-client => ereport-client}/Cargo.toml (95%) rename clients/{ereporter-client => ereport-client}/src/lib.rs (93%) rename openapi/{ereporter/ereporter-1.0.0-e64494.json => ereport/ereport-1.0.0-e41934.json} (99%) create mode 120000 openapi/ereport/ereport-latest.json delete mode 120000 openapi/ereporter/ereporter-latest.json diff --git a/Cargo.lock b/Cargo.lock index 95fca6144ec..699d16e4e4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3035,19 +3035,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "ereport-types" -version = "0.1.0" -dependencies = [ - "omicron-uuid-kinds", - "omicron-workspace-hack", - "schemars", - "serde", - "serde_json", - "uuid", -] - -[[package]] -name = "ereporter-api" +name = "ereport-api" version = "0.1.0" dependencies = [ "dropshot 0.16.0", @@ -3063,7 +3051,7 @@ dependencies = [ ] [[package]] -name = "ereporter-client" +name = "ereport-client" version = "0.1.0" dependencies = [ "chrono", @@ -3081,6 +3069,18 @@ dependencies = [ "uuid", ] +[[package]] +name = "ereport-types" +version = "0.1.0" +dependencies = [ + "omicron-uuid-kinds", + "omicron-workspace-hack", + "schemars", + "serde", + "serde_json", + "uuid", +] + [[package]] name = "errno" version = "0.3.9" @@ -6963,7 +6963,7 @@ dependencies = [ "chrono", "clap", "dropshot 0.16.0", - "ereporter-api", + "ereport-api", "expectorate", "futures", "gateway-api", @@ -7084,7 +7084,7 @@ dependencies = [ "dns-service-client", "dpd-client", "dropshot 0.16.0", - "ereporter-client", + "ereport-client", "expectorate", "fatfs", "futures", @@ -7429,7 +7429,7 @@ dependencies = [ "dns-service-client", "dpd-client", "dropshot 0.16.0", - "ereporter-api", + "ereport-api", "expectorate", "flate2", "flume", @@ -7792,7 +7792,7 @@ dependencies = [ "debug-ignore", "dns-server-api", "dropshot 0.16.0", - "ereporter-api", + "ereport-api", "fs-err", "gateway-api", "hex", diff --git a/Cargo.toml b/Cargo.toml index 6c9ccd561a0..3d1a6789344 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ "clients/ddm-admin-client", "clients/dns-service-client", "clients/dpd-client", - "clients/ereporter-client", + "clients/ereport-client", "clients/gateway-client", "clients/installinator-client", "clients/nexus-client", @@ -153,7 +153,7 @@ default-members = [ "clients/ddm-admin-client", "clients/dns-service-client", "clients/dpd-client", - "clients/ereporter-client", + "clients/ereport-client", "clients/gateway-client", "clients/installinator-client", "clients/nexus-client", @@ -391,8 +391,8 @@ dpd-client = { path = "clients/dpd-client" } dropshot = { version = "0.16.0", features = [ "usdt-probes" ] } dyn-clone = "1.0.19" either = "1.14.0" -ereporter-api = { path = "ereport/api" } -ereporter-client = { path = "clients/ereporter-client" } +ereport-api = { path = "ereport/api" } +ereport-client = { path = "clients/ereport-client" } ereport-types = { path = "ereport/types" } expectorate = "1.1.0" fatfs = "0.3.6" diff --git a/clients/ereporter-client/Cargo.toml b/clients/ereport-client/Cargo.toml similarity index 95% rename from clients/ereporter-client/Cargo.toml rename to clients/ereport-client/Cargo.toml index acc5abaa4f8..5cc61ab5974 100644 --- a/clients/ereporter-client/Cargo.toml +++ b/clients/ereport-client/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ereporter-client" +name = "ereport-client" version = "0.1.0" edition = "2024" diff --git a/clients/ereporter-client/src/lib.rs b/clients/ereport-client/src/lib.rs similarity index 93% rename from clients/ereporter-client/src/lib.rs rename to clients/ereport-client/src/lib.rs index 9c3e625637c..6b890ee2517 100644 --- a/clients/ereporter-client/src/lib.rs +++ b/clients/ereport-client/src/lib.rs @@ -3,7 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. progenitor::generate_api!( - spec = "../../openapi/ereporter/ereporter-latest.json", + spec = "../../openapi/ereport/ereport-latest.json", inner_type = slog::Logger, derives = [schemars::JsonSchema, Clone, Eq, PartialEq], pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { diff --git a/dev-tools/ls-apis/api-manifest.toml b/dev-tools/ls-apis/api-manifest.toml index 7e5d0445af7..1738c88ba3a 100644 --- a/dev-tools/ls-apis/api-manifest.toml +++ b/dev-tools/ls-apis/api-manifest.toml @@ -271,9 +271,9 @@ repo is not currently open source. """ [[apis]] -client_package_name = "ereporter-client" -label = "Ereporter" -server_package_name = "ereporter-api" +client_package_name = "ereport-client" +label = "ereport" +server_package_name = "ereport-api" versioned_how = "server" notes = """ Implemented by sled-agents and by MGS, and consumed by Nexus to collect \ diff --git a/dev-tools/openapi-manager/Cargo.toml b/dev-tools/openapi-manager/Cargo.toml index 4dea84a0ea8..288e68e4fd3 100644 --- a/dev-tools/openapi-manager/Cargo.toml +++ b/dev-tools/openapi-manager/Cargo.toml @@ -18,7 +18,7 @@ cockroach-admin-api.workspace = true debug-ignore.workspace = true dns-server-api.workspace = true dropshot.workspace = true -ereporter-api.workspace = true +ereport-api.workspace = true hex.workspace = true fs-err.workspace = true gateway-api.workspace = true diff --git a/dev-tools/openapi-manager/src/omicron.rs b/dev-tools/openapi-manager/src/omicron.rs index 7179c328a29..fb39e8891dd 100644 --- a/dev-tools/openapi-manager/src/omicron.rs +++ b/dev-tools/openapi-manager/src/omicron.rs @@ -86,15 +86,15 @@ pub fn all_apis() -> Vec { extra_validation: None, }, ManagedApiConfig { - title: "Ereporter API", + title: "Ereport Reporter API", versions: Versions::new_versioned( - ereporter_api::supported_versions() + ereport_api::supported_versions() ), description: "API for ereport producers", boundary: ApiBoundary::Internal, api_description: - ereporter_api::ereporter_api_mod::stub_api_description, - ident: "ereporter", + ereport_api::ereport_api_mod::stub_api_description, + ident: "ereport", extra_validation: None, }, ManagedApiConfig { diff --git a/ereport/api/Cargo.toml b/ereport/api/Cargo.toml index 872e7be5a7b..cf154dc5e25 100644 --- a/ereport/api/Cargo.toml +++ b/ereport/api/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ereporter-api" +name = "ereport-api" version = "0.1.0" edition = "2024" diff --git a/ereport/api/src/lib.rs b/ereport/api/src/lib.rs index 1cfbd949a1c..145ca37f450 100644 --- a/ereport/api/src/lib.rs +++ b/ereport/api/src/lib.rs @@ -52,7 +52,7 @@ api_versions!([ /// API for ereport producers. #[dropshot::api_description] -pub trait EreporterApi { +pub trait EreportApi { type Context; /// Collect a tranche of ereports from this reporter. @@ -69,7 +69,7 @@ pub trait EreporterApi { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct ReporterPath { - /// The UUID of the reporter from which to collct ereports. + /// The UUID of the reporter from which to collect ereports. pub reporter_id: Uuid, } diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index 3ad46da22b4..bbe88ca07cc 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -14,7 +14,7 @@ camino.workspace = true chrono.workspace = true clap.workspace = true dropshot.workspace = true -ereporter-api.workspace = true +ereport-api.workspace = true futures.workspace = true gateway-api.workspace = true gateway-messages.workspace = true diff --git a/nexus/Cargo.toml b/nexus/Cargo.toml index 14e731fb5e4..55eff072040 100644 --- a/nexus/Cargo.toml +++ b/nexus/Cargo.toml @@ -31,7 +31,7 @@ crucible-pantry-client.workspace = true crucible-common.workspace = true dns-service-client.workspace = true dpd-client.workspace = true -ereporter-client.workspace = true +ereport-client.workspace = true mg-admin-client.workspace = true dropshot.workspace = true fatfs.workspace = true diff --git a/openapi/ereporter/ereporter-1.0.0-e64494.json b/openapi/ereport/ereport-1.0.0-e41934.json similarity index 99% rename from openapi/ereporter/ereporter-1.0.0-e64494.json rename to openapi/ereport/ereport-1.0.0-e41934.json index d3c641ae624..be4cce56350 100644 --- a/openapi/ereporter/ereporter-1.0.0-e64494.json +++ b/openapi/ereport/ereport-1.0.0-e41934.json @@ -1,7 +1,7 @@ { "openapi": "3.0.3", "info": { - "title": "Ereporter API", + "title": "Ereport Reporter API", "description": "API for ereport producers", "contact": { "url": "https://oxide.computer", @@ -18,7 +18,7 @@ { "in": "path", "name": "reporter_id", - "description": "The UUID of the reporter from which to collct ereports.", + "description": "The UUID of the reporter from which to collect ereports.", "required": true, "schema": { "type": "string", diff --git a/openapi/ereport/ereport-latest.json b/openapi/ereport/ereport-latest.json new file mode 120000 index 00000000000..bb893cfafb5 --- /dev/null +++ b/openapi/ereport/ereport-latest.json @@ -0,0 +1 @@ +ereport-1.0.0-e41934.json \ No newline at end of file diff --git a/openapi/ereporter/ereporter-latest.json b/openapi/ereporter/ereporter-latest.json deleted file mode 120000 index 14f13401191..00000000000 --- a/openapi/ereporter/ereporter-latest.json +++ /dev/null @@ -1 +0,0 @@ -ereporter-1.0.0-e64494.json \ No newline at end of file diff --git a/sled-agent/Cargo.toml b/sled-agent/Cargo.toml index 3f2a5275c85..56368eda10d 100644 --- a/sled-agent/Cargo.toml +++ b/sled-agent/Cargo.toml @@ -31,7 +31,7 @@ dns-service-client.workspace = true dpd-client.workspace = true display-error-chain.workspace = true dropshot.workspace = true -ereporter-api.workspace = true +ereport-api.workspace = true flate2.workspace = true flume.workspace = true futures.workspace = true