diff --git a/Cargo.lock b/Cargo.lock index 9ccc585826e..fa352d4a6e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1458,7 +1458,9 @@ dependencies = [ "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", + "openapi-manager-types", "schemars", + "semver 1.0.26", "serde", ] @@ -1607,7 +1609,9 @@ dependencies = [ "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", + "openapi-manager-types", "schemars", + "semver 1.0.26", "serde", ] @@ -7239,7 +7243,9 @@ dependencies = [ "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", + "openapi-manager-types", "schemars", + "semver 1.0.26", "serde", ] @@ -8994,7 +9000,9 @@ dependencies = [ "dropshot", "omicron-common", "omicron-workspace-hack", + "openapi-manager-types", "schemars", + "semver 1.0.26", "serde", "uuid", ] @@ -12276,7 +12284,9 @@ dependencies = [ "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", + "openapi-manager-types", "schemars", + "semver 1.0.26", "serde", "sled-agent-types", "sled-diagnostics", diff --git a/clickhouse-admin/api/Cargo.toml b/clickhouse-admin/api/Cargo.toml index a5d1dca2024..f3b7dd83a18 100644 --- a/clickhouse-admin/api/Cargo.toml +++ b/clickhouse-admin/api/Cargo.toml @@ -13,5 +13,7 @@ dropshot.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true +openapi-manager-types.workspace = true schemars.workspace = true +semver.workspace = true serde.workspace = true diff --git a/clickhouse-admin/api/src/lib.rs b/clickhouse-admin/api/src/lib.rs index fbd8a78a0a5..baefdb497fc 100644 --- a/clickhouse-admin/api/src/lib.rs +++ b/clickhouse-admin/api/src/lib.rs @@ -13,6 +13,41 @@ use dropshot::{ HttpResponseUpdatedNoContent, Path, Query, RequestContext, TypedBody, }; use omicron_common::api::external::Generation; +use openapi_manager_types::{ + SupportedVersion, SupportedVersions, api_versions, +}; + +api_versions!([ + // NOTE: These versions will be used across **all three** APIs defined in + // this file. When we need to add the next version, consider carefully if + // these APIs should be split into separate modules or crates with their + // own 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), // NOTE: read the note at the start of this macro! + (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 interface for our clickhouse-admin-keeper server /// diff --git a/clickhouse-admin/src/lib.rs b/clickhouse-admin/src/lib.rs index 88168911ba3..9f66140efda 100644 --- a/clickhouse-admin/src/lib.rs +++ b/clickhouse-admin/src/lib.rs @@ -68,6 +68,12 @@ pub async fn start_server_admin_server( log.new(slog::o!("component" => "dropshot")), ) .config(server_config.dropshot) + .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( + dropshot::ClientSpecifiesVersionInHeader::new( + omicron_common::api::VERSION_HEADER, + clickhouse_admin_api::VERSION_INITIAL, + ), + ))) .start() .map_err(StartError::InitializeHttpServer) } @@ -105,6 +111,12 @@ pub async fn start_keeper_admin_server( log.new(slog::o!("component" => "dropshot")), ) .config(server_config.dropshot) + .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( + dropshot::ClientSpecifiesVersionInHeader::new( + omicron_common::api::VERSION_HEADER, + clickhouse_admin_api::VERSION_INITIAL, + ), + ))) .start() .map_err(StartError::InitializeHttpServer) } @@ -142,6 +154,12 @@ pub async fn start_single_admin_server( log.new(slog::o!("component" => "dropshot")), ) .config(server_config.dropshot) + .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( + dropshot::ClientSpecifiesVersionInHeader::new( + omicron_common::api::VERSION_HEADER, + clickhouse_admin_api::VERSION_INITIAL, + ), + ))) .start() .map_err(StartError::InitializeHttpServer) } diff --git a/clients/clickhouse-admin-keeper-client/src/lib.rs b/clients/clickhouse-admin-keeper-client/src/lib.rs index 5c4d3692fab..68bcbbaa079 100644 --- a/clients/clickhouse-admin-keeper-client/src/lib.rs +++ b/clients/clickhouse-admin-keeper-client/src/lib.rs @@ -6,7 +6,7 @@ //! running in an omicron zone. progenitor::generate_api!( - spec = "../../openapi/clickhouse-admin-keeper.json", + spec = "../../openapi/clickhouse-admin-keeper/clickhouse-admin-keeper-latest.json", interface = Positional, inner_type = slog::Logger, pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { diff --git a/clients/clickhouse-admin-server-client/src/lib.rs b/clients/clickhouse-admin-server-client/src/lib.rs index af9d5aae988..e8da8d250f6 100644 --- a/clients/clickhouse-admin-server-client/src/lib.rs +++ b/clients/clickhouse-admin-server-client/src/lib.rs @@ -6,7 +6,7 @@ //! running in an omicron zone. progenitor::generate_api!( - spec = "../../openapi/clickhouse-admin-server.json", + spec = "../../openapi/clickhouse-admin-server/clickhouse-admin-server-latest.json", interface = Positional, inner_type = slog::Logger, pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { diff --git a/clients/clickhouse-admin-single-client/src/lib.rs b/clients/clickhouse-admin-single-client/src/lib.rs index ae0a3850175..396c9d68b2b 100644 --- a/clients/clickhouse-admin-single-client/src/lib.rs +++ b/clients/clickhouse-admin-single-client/src/lib.rs @@ -6,7 +6,7 @@ //! ClickHouse database. progenitor::generate_api!( - spec = "../../openapi/clickhouse-admin-single.json", + spec = "../../openapi/clickhouse-admin-single/clickhouse-admin-single-latest.json", interface = Positional, inner_type = slog::Logger, pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { diff --git a/clients/cockroach-admin-client/src/lib.rs b/clients/cockroach-admin-client/src/lib.rs index bf007b5f146..02edf2e6248 100644 --- a/clients/cockroach-admin-client/src/lib.rs +++ b/clients/cockroach-admin-client/src/lib.rs @@ -5,7 +5,7 @@ //! Interface for making API requests to an Omicron CockroachDB admin server progenitor::generate_api!( - spec = "../../openapi/cockroach-admin.json", + spec = "../../openapi/cockroach-admin/cockroach-admin-latest.json", interface = Positional, inner_type = slog::Logger, pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { diff --git a/clients/ntp-admin-client/src/lib.rs b/clients/ntp-admin-client/src/lib.rs index 9a2c028c514..4cdc70d6d99 100644 --- a/clients/ntp-admin-client/src/lib.rs +++ b/clients/ntp-admin-client/src/lib.rs @@ -5,7 +5,7 @@ //! Interface for making API requests to an Omicron NTP admin server progenitor::generate_api!( - spec = "../../openapi/ntp-admin.json", + spec = "../../openapi/ntp-admin/ntp-admin-latest.json", interface = Positional, inner_type = slog::Logger, pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { diff --git a/clients/oximeter-client/src/lib.rs b/clients/oximeter-client/src/lib.rs index 3c9df960024..764e2f7d7c5 100644 --- a/clients/oximeter-client/src/lib.rs +++ b/clients/oximeter-client/src/lib.rs @@ -7,7 +7,7 @@ //! Interface for API requests to an Oximeter metric collection server progenitor::generate_api!( - spec = "../../openapi/oximeter.json", + spec = "../../openapi/oximeter/oximeter-latest.json", interface = Positional, inner_type = slog::Logger, pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { diff --git a/clients/sled-agent-client/src/lib.rs b/clients/sled-agent-client/src/lib.rs index 948d246e734..faa09fbf889 100644 --- a/clients/sled-agent-client/src/lib.rs +++ b/clients/sled-agent-client/src/lib.rs @@ -15,7 +15,7 @@ use uuid::Uuid; pub use propolis_client::{CrucibleOpts, VolumeConstructionRequest}; progenitor::generate_api!( - spec = "../../openapi/sled-agent.json", + spec = "../../openapi/sled-agent/sled-agent-latest.json", interface = Positional, inner_type = slog::Logger, pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { diff --git a/cockroach-admin/api/Cargo.toml b/cockroach-admin/api/Cargo.toml index da2b9404082..09852b45ef4 100644 --- a/cockroach-admin/api/Cargo.toml +++ b/cockroach-admin/api/Cargo.toml @@ -14,5 +14,7 @@ http.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true +openapi-manager-types.workspace = true schemars.workspace = true +semver.workspace = true serde.workspace = true diff --git a/cockroach-admin/api/src/lib.rs b/cockroach-admin/api/src/lib.rs index 18b51ac183c..942bb39aa3c 100644 --- a/cockroach-admin/api/src/lib.rs +++ b/cockroach-admin/api/src/lib.rs @@ -8,9 +8,39 @@ use dropshot::{ TypedBody, }; use omicron_uuid_kinds::OmicronZoneUuid; +use openapi_manager_types::{ + SupportedVersion, SupportedVersions, api_versions, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +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. + #[dropshot::api_description] pub trait CockroachAdminApi { type Context; diff --git a/cockroach-admin/src/lib.rs b/cockroach-admin/src/lib.rs index 10cecf56a05..9591e01433b 100644 --- a/cockroach-admin/src/lib.rs +++ b/cockroach-admin/src/lib.rs @@ -69,6 +69,12 @@ pub async fn start_server( log.new(slog::o!("component" => "dropshot")), ) .config(server_config.dropshot) + .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( + dropshot::ClientSpecifiesVersionInHeader::new( + omicron_common::api::VERSION_HEADER, + cockroach_admin_api::VERSION_INITIAL, + ), + ))) .start() .map_err(StartError::InitializeHttpServer) } diff --git a/common/src/api/mod.rs b/common/src/api/mod.rs index ee3776e15b9..44ca3671174 100644 --- a/common/src/api/mod.rs +++ b/common/src/api/mod.rs @@ -6,3 +6,7 @@ pub mod external; pub mod internal; + +/// API versioning header name used across Omicron APIs. +pub const VERSION_HEADER: http::HeaderName = + http::HeaderName::from_static("api-version"); diff --git a/dev-tools/openapi-manager/src/omicron.rs b/dev-tools/openapi-manager/src/omicron.rs index 8b446099b71..e31956b5e73 100644 --- a/dev-tools/openapi-manager/src/omicron.rs +++ b/dev-tools/openapi-manager/src/omicron.rs @@ -36,7 +36,9 @@ pub fn all_apis() -> Vec { }, ManagedApiConfig { title: "ClickHouse Cluster Admin Keeper API", - versions: Versions::new_lockstep(semver::Version::new(0, 0, 1)), + versions: Versions::new_versioned( + clickhouse_admin_api::supported_versions(), + ), description: "API for interacting with the Oxide \ control plane's ClickHouse cluster keepers", boundary: ApiBoundary::Internal, @@ -47,7 +49,9 @@ pub fn all_apis() -> Vec { }, ManagedApiConfig { title: "ClickHouse Cluster Admin Server API", - versions: Versions::new_lockstep(semver::Version::new(0, 0, 1)), + versions: Versions::new_versioned( + clickhouse_admin_api::supported_versions(), + ), description: "API for interacting with the Oxide \ control plane's ClickHouse cluster replica servers", boundary: ApiBoundary::Internal, @@ -58,7 +62,9 @@ pub fn all_apis() -> Vec { }, ManagedApiConfig { title: "ClickHouse Single-Node Admin Server API", - versions: Versions::new_lockstep(semver::Version::new(0, 0, 1)), + versions: Versions::new_versioned( + clickhouse_admin_api::supported_versions(), + ), description: "API for interacting with the Oxide \ control plane's single-node ClickHouse database", boundary: ApiBoundary::Internal, @@ -69,7 +75,9 @@ pub fn all_apis() -> Vec { }, ManagedApiConfig { title: "CockroachDB Cluster Admin API", - versions: Versions::new_lockstep(semver::Version::new(0, 0, 1)), + versions: Versions::new_versioned( + cockroach_admin_api::supported_versions(), + ), description: "API for interacting with the Oxide \ control plane's CockroachDB cluster", boundary: ApiBoundary::Internal, @@ -130,7 +138,9 @@ pub fn all_apis() -> Vec { }, ManagedApiConfig { title: "NTP Admin API", - versions: Versions::new_lockstep(semver::Version::new(0, 0, 1)), + versions: Versions::new_versioned( + ntp_admin_api::supported_versions(), + ), description: "API for interacting with NTP", boundary: ApiBoundary::Internal, api_description: ntp_admin_api_mod::stub_api_description, @@ -139,7 +149,9 @@ pub fn all_apis() -> Vec { }, ManagedApiConfig { title: "Oxide Oximeter API", - versions: Versions::new_lockstep(semver::Version::new(0, 0, 1)), + versions: Versions::new_versioned( + oximeter_api::supported_versions(), + ), description: "API for interacting with oximeter", boundary: ApiBoundary::Internal, api_description: oximeter_api_mod::stub_api_description, @@ -157,7 +169,9 @@ pub fn all_apis() -> Vec { }, ManagedApiConfig { title: "Oxide Sled Agent API", - versions: Versions::new_lockstep(semver::Version::new(0, 0, 1)), + versions: Versions::new_versioned( + sled_agent_api::supported_versions(), + ), description: "API for interacting with individual sleds", boundary: ApiBoundary::Internal, api_description: sled_agent_api_mod::stub_api_description, diff --git a/dev-tools/openapi-manager/src/spec_files_generic.rs b/dev-tools/openapi-manager/src/spec_files_generic.rs index f3f616d07bf..d9b227450b4 100644 --- a/dev-tools/openapi-manager/src/spec_files_generic.rs +++ b/dev-tools/openapi-manager/src/spec_files_generic.rs @@ -400,23 +400,32 @@ impl<'a, T: ApiLoad + AsRawFiles> ApiSpecFilesBuilder<'a, T> { basename: &str, ) -> Option { match ApiSpecFileName::parse_lockstep(&self.apis, basename) { - Err( - warning @ (BadLockstepFileName::NoSuchApi - | BadLockstepFileName::NotLockstep), - ) if T::MISCONFIGURATIONS_ALLOWED => { - // When we're looking at the blessed files, the caller provides - // `misconfigurations_okay: true` and we treat these as - // warnings because the configuration for an API may have - // changed between the blessed files and the local changes. - // - // - NoSuchApi: somebody is deleting an API locally - // - NotLockstep: somebody is converting a lockstep API to a - // versioned one - let warning = anyhow!(warning) - .context(format!("skipping file {:?}", basename)); + // When we're looking at the blessed files, the caller provides + // `misconfigurations_okay: true` and we treat these as + // warnings because the configuration for an API may have + // changed between the blessed files and the local changes. + Err(warning @ BadLockstepFileName::NoSuchApi) + if T::MISCONFIGURATIONS_ALLOWED => + { + let warning = anyhow!( + "skipping file {basename:?}: {warning} \ + (this is expected if you are deleting an API)" + ); self.load_warning(warning); None } + Err(warning @ BadLockstepFileName::NotLockstep) + if T::MISCONFIGURATIONS_ALLOWED => + { + let warning = anyhow!( + "skipping file {basename:?}: {warning} \ + (this is expected if you are converting \ + a lockstep API to a versioned one)" + ); + self.load_warning(warning); + None + } + Err(warning @ BadLockstepFileName::MissingJsonSuffix) => { // Even if the caller didn't provide `problems_okay: true`, it's // not a big deal to have an extra file here. This could be an diff --git a/dns-server/src/lib.rs b/dns-server/src/lib.rs index ad5d49c138b..dde10a6387a 100644 --- a/dns-server/src/lib.rs +++ b/dns-server/src/lib.rs @@ -97,9 +97,7 @@ pub async fn start_servers( .config(dropshot_config.clone()) .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( dropshot::ClientSpecifiesVersionInHeader::new( - "api-version" - .parse::() - .expect("api-version is a valid header name"), + omicron_common::api::VERSION_HEADER, dns_server_api::VERSION_SOA_AND_NS, ), ))) diff --git a/internal-dns/resolver/src/resolver.rs b/internal-dns/resolver/src/resolver.rs index 9df83dc4968..86a7eafbad3 100644 --- a/internal-dns/resolver/src/resolver.rs +++ b/internal-dns/resolver/src/resolver.rs @@ -875,9 +875,7 @@ mod test { .config(config_dropshot) .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( dropshot::ClientSpecifiesVersionInHeader::new( - "api-version" - .parse::() - .expect("api-version is a valid header name"), + omicron_common::api::VERSION_HEADER, dns_server_api::VERSION_SOA_AND_NS, ), ))) diff --git a/ntp-admin/api/Cargo.toml b/ntp-admin/api/Cargo.toml index 3ef5615c641..6f7fbe9fe6c 100644 --- a/ntp-admin/api/Cargo.toml +++ b/ntp-admin/api/Cargo.toml @@ -14,5 +14,7 @@ ntp-admin-types.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true +openapi-manager-types.workspace = true schemars.workspace = true +semver.workspace = true serde.workspace = true diff --git a/ntp-admin/api/src/lib.rs b/ntp-admin/api/src/lib.rs index 07c5867339d..aff258b4460 100644 --- a/ntp-admin/api/src/lib.rs +++ b/ntp-admin/api/src/lib.rs @@ -3,6 +3,36 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use dropshot::{HttpError, HttpResponseOk, RequestContext}; +use openapi_manager_types::{ + SupportedVersion, SupportedVersions, api_versions, +}; + +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. #[dropshot::api_description] pub trait NtpAdminApi { diff --git a/ntp-admin/src/lib.rs b/ntp-admin/src/lib.rs index 5d79987bf6a..ef9fe1b3b65 100644 --- a/ntp-admin/src/lib.rs +++ b/ntp-admin/src/lib.rs @@ -58,6 +58,12 @@ pub async fn start_server(server_config: Config) -> Result { log.new(slog::o!("component" => "dropshot")), ) .config(server_config.dropshot) + .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( + dropshot::ClientSpecifiesVersionInHeader::new( + omicron_common::api::VERSION_HEADER, + ntp_admin_api::VERSION_INITIAL, + ), + ))) .start() .map_err(StartError::InitializeHttpServer) } diff --git a/openapi/clickhouse-admin-keeper.json b/openapi/clickhouse-admin-keeper/clickhouse-admin-keeper-1.0.0-169173.json similarity index 99% rename from openapi/clickhouse-admin-keeper.json rename to openapi/clickhouse-admin-keeper/clickhouse-admin-keeper-1.0.0-169173.json index 5099e2fe595..e3296068963 100644 --- a/openapi/clickhouse-admin-keeper.json +++ b/openapi/clickhouse-admin-keeper/clickhouse-admin-keeper-1.0.0-169173.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "0.0.1" + "version": "1.0.0" }, "paths": { "/4lw-conf": { diff --git a/openapi/clickhouse-admin-keeper/clickhouse-admin-keeper-latest.json b/openapi/clickhouse-admin-keeper/clickhouse-admin-keeper-latest.json new file mode 120000 index 00000000000..81e0bb08a07 --- /dev/null +++ b/openapi/clickhouse-admin-keeper/clickhouse-admin-keeper-latest.json @@ -0,0 +1 @@ +clickhouse-admin-keeper-1.0.0-169173.json \ No newline at end of file diff --git a/openapi/clickhouse-admin-server.json b/openapi/clickhouse-admin-server/clickhouse-admin-server-1.0.0-dcea9c.json similarity index 99% rename from openapi/clickhouse-admin-server.json rename to openapi/clickhouse-admin-server/clickhouse-admin-server-1.0.0-dcea9c.json index 5b63767bd23..6e61df7820e 100644 --- a/openapi/clickhouse-admin-server.json +++ b/openapi/clickhouse-admin-server/clickhouse-admin-server-1.0.0-dcea9c.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "0.0.1" + "version": "1.0.0" }, "paths": { "/config": { diff --git a/openapi/clickhouse-admin-server/clickhouse-admin-server-latest.json b/openapi/clickhouse-admin-server/clickhouse-admin-server-latest.json new file mode 120000 index 00000000000..6e92f6bffbf --- /dev/null +++ b/openapi/clickhouse-admin-server/clickhouse-admin-server-latest.json @@ -0,0 +1 @@ +clickhouse-admin-server-1.0.0-dcea9c.json \ No newline at end of file diff --git a/openapi/clickhouse-admin-single.json b/openapi/clickhouse-admin-single/clickhouse-admin-single-1.0.0-712a53.json similarity index 99% rename from openapi/clickhouse-admin-single.json rename to openapi/clickhouse-admin-single/clickhouse-admin-single-1.0.0-712a53.json index c6b99da245d..118d5af5dbe 100644 --- a/openapi/clickhouse-admin-single.json +++ b/openapi/clickhouse-admin-single/clickhouse-admin-single-1.0.0-712a53.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "0.0.1" + "version": "1.0.0" }, "paths": { "/init": { diff --git a/openapi/clickhouse-admin-single/clickhouse-admin-single-latest.json b/openapi/clickhouse-admin-single/clickhouse-admin-single-latest.json new file mode 120000 index 00000000000..e3e28570691 --- /dev/null +++ b/openapi/clickhouse-admin-single/clickhouse-admin-single-latest.json @@ -0,0 +1 @@ +clickhouse-admin-single-1.0.0-712a53.json \ No newline at end of file diff --git a/openapi/cockroach-admin.json b/openapi/cockroach-admin/cockroach-admin-1.0.0-dc9acb.json similarity index 99% rename from openapi/cockroach-admin.json rename to openapi/cockroach-admin/cockroach-admin-1.0.0-dc9acb.json index 80c50db0f1f..6b2fab93abc 100644 --- a/openapi/cockroach-admin.json +++ b/openapi/cockroach-admin/cockroach-admin-1.0.0-dc9acb.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "0.0.1" + "version": "1.0.0" }, "paths": { "/cluster/init": { diff --git a/openapi/cockroach-admin/cockroach-admin-latest.json b/openapi/cockroach-admin/cockroach-admin-latest.json new file mode 120000 index 00000000000..4a81b27dac9 --- /dev/null +++ b/openapi/cockroach-admin/cockroach-admin-latest.json @@ -0,0 +1 @@ +cockroach-admin-1.0.0-dc9acb.json \ No newline at end of file diff --git a/openapi/ntp-admin.json b/openapi/ntp-admin/ntp-admin-1.0.0-aeffc2.json similarity index 99% rename from openapi/ntp-admin.json rename to openapi/ntp-admin/ntp-admin-1.0.0-aeffc2.json index eae66021e91..97fc34581cc 100644 --- a/openapi/ntp-admin.json +++ b/openapi/ntp-admin/ntp-admin-1.0.0-aeffc2.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "0.0.1" + "version": "1.0.0" }, "paths": { "/timesync": { diff --git a/openapi/ntp-admin/ntp-admin-latest.json b/openapi/ntp-admin/ntp-admin-latest.json new file mode 120000 index 00000000000..30138bae0ea --- /dev/null +++ b/openapi/ntp-admin/ntp-admin-latest.json @@ -0,0 +1 @@ +ntp-admin-1.0.0-aeffc2.json \ No newline at end of file diff --git a/openapi/oximeter.json b/openapi/oximeter/oximeter-1.0.0-8e3b9c.json similarity index 99% rename from openapi/oximeter.json rename to openapi/oximeter/oximeter-1.0.0-8e3b9c.json index b51c56b667a..e78c47d07f0 100644 --- a/openapi/oximeter.json +++ b/openapi/oximeter/oximeter-1.0.0-8e3b9c.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "0.0.1" + "version": "1.0.0" }, "paths": { "/info": { diff --git a/openapi/oximeter/oximeter-latest.json b/openapi/oximeter/oximeter-latest.json new file mode 120000 index 00000000000..e07d9a8f248 --- /dev/null +++ b/openapi/oximeter/oximeter-latest.json @@ -0,0 +1 @@ +oximeter-1.0.0-8e3b9c.json \ No newline at end of file diff --git a/openapi/sled-agent.json b/openapi/sled-agent/sled-agent-1.0.0-2da304.json similarity index 99% rename from openapi/sled-agent.json rename to openapi/sled-agent/sled-agent-1.0.0-2da304.json index 22bd3c8b072..23fcdb15b7a 100644 --- a/openapi/sled-agent.json +++ b/openapi/sled-agent/sled-agent-1.0.0-2da304.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "0.0.1" + "version": "1.0.0" }, "paths": { "/artifacts": { diff --git a/openapi/sled-agent/sled-agent-latest.json b/openapi/sled-agent/sled-agent-latest.json new file mode 120000 index 00000000000..41b0de8863b --- /dev/null +++ b/openapi/sled-agent/sled-agent-latest.json @@ -0,0 +1 @@ +sled-agent-1.0.0-2da304.json \ No newline at end of file diff --git a/oximeter/api/Cargo.toml b/oximeter/api/Cargo.toml index 72189aa6459..6df6bcda2c5 100644 --- a/oximeter/api/Cargo.toml +++ b/oximeter/api/Cargo.toml @@ -11,6 +11,8 @@ chrono.workspace = true dropshot.workspace = true omicron-common.workspace = true omicron-workspace-hack.workspace = true +openapi-manager-types.workspace = true schemars.workspace = true +semver.workspace = true serde.workspace = true uuid.workspace = true diff --git a/oximeter/api/src/lib.rs b/oximeter/api/src/lib.rs index f47a5ba07ee..e0b36007ed7 100644 --- a/oximeter/api/src/lib.rs +++ b/oximeter/api/src/lib.rs @@ -8,11 +8,41 @@ use dropshot::{ PaginationParams, Query, RequestContext, ResultsPage, }; use omicron_common::api::internal::nexus::ProducerEndpoint; +use openapi_manager_types::{ + SupportedVersion, SupportedVersions, api_versions, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{net::SocketAddr, time::Duration}; 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. + #[dropshot::api_description] pub trait OximeterApi { type Context; diff --git a/oximeter/collector/src/lib.rs b/oximeter/collector/src/lib.rs index 024b0bcd338..73cc220575d 100644 --- a/oximeter/collector/src/lib.rs +++ b/oximeter/collector/src/lib.rs @@ -339,6 +339,12 @@ impl Oximeter { bind_address: SocketAddr::V6(args.address), ..Default::default() }) + .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( + dropshot::ClientSpecifiesVersionInHeader::new( + omicron_common::api::VERSION_HEADER, + oximeter_api::VERSION_INITIAL, + ), + ))) .start() .map_err(|e| Error::Server(e.to_string()))?; @@ -451,6 +457,12 @@ impl Oximeter { bind_address: SocketAddr::V6(args.address), ..Default::default() }) + .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( + dropshot::ClientSpecifiesVersionInHeader::new( + omicron_common::api::VERSION_HEADER, + oximeter_api::VERSION_INITIAL, + ), + ))) .start() .map_err(|e| Error::Server(e.to_string()))?; info!(log, "started oximeter standalone server"); diff --git a/sled-agent/api/Cargo.toml b/sled-agent/api/Cargo.toml index 9077419faf3..eb682524e57 100644 --- a/sled-agent/api/Cargo.toml +++ b/sled-agent/api/Cargo.toml @@ -22,3 +22,5 @@ sled-hardware-types.workspace = true sled-diagnostics.workspace = true tufaceous-artifact.workspace = true uuid.workspace = true +openapi-manager-types.workspace = true +semver.workspace = true diff --git a/sled-agent/api/src/lib.rs b/sled-agent/api/src/lib.rs index 650cc04b010..f66b40048c7 100644 --- a/sled-agent/api/src/lib.rs +++ b/sled-agent/api/src/lib.rs @@ -30,6 +30,9 @@ use omicron_common::{ use omicron_uuid_kinds::{ DatasetUuid, PropolisUuid, SupportBundleUuid, ZpoolUuid, }; +use openapi_manager_types::{ + SupportedVersion, SupportedVersions, api_versions, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use sled_agent_types::{ @@ -51,6 +54,33 @@ use sled_diagnostics::SledDiagnosticsQueryOutput; use tufaceous_artifact::ArtifactHash; 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. + // Host OS images are just over 800 MiB currently; set this to 2 GiB to give // some breathing room. const HOST_OS_IMAGE_MAX_BYTES: usize = 2 * 1024 * 1024 * 1024; diff --git a/sled-agent/src/server.rs b/sled-agent/src/server.rs index 15a5c2f784d..1ca4ad3f697 100644 --- a/sled-agent/src/server.rs +++ b/sled-agent/src/server.rs @@ -76,6 +76,12 @@ impl Server { let http_server = dropshot::ServerBuilder::new(http_api(), sled_agent, dropshot_log) .config(dropshot_config) + .version_policy(dropshot::VersionPolicy::Dynamic(Box::new( + dropshot::ClientSpecifiesVersionInHeader::new( + omicron_common::api::VERSION_HEADER, + sled_agent_api::VERSION_INITIAL, + ), + ))) .start() .map_err(|error| format!("initializing server: {}", error))?;