From fcf53ca41799120b6ca09c40f67b8a9de7bfe79c Mon Sep 17 00:00:00 2001 From: Adam Leventhal Date: Wed, 19 Jan 2022 21:19:46 -0800 Subject: [PATCH] Make naming conform to openapi-lint (#610) --- Cargo.lock | 13 +- common/src/api/external/mod.rs | 43 ++-- nexus/Cargo.toml | 2 +- nexus/src/external_api/console_api.rs | 1 - nexus/src/external_api/params.rs | 15 -- nexus/src/external_api/views.rs | 9 - nexus/tests/integration_tests/vpc_subnets.rs | 4 +- openapi/nexus-internal.json | 44 ++-- openapi/nexus.json | 212 +++++++++---------- openapi/sled-agent.json | 20 +- oximeter/collector/Cargo.toml | 2 +- oximeter/collector/src/lib.rs | 6 +- oximeter/oximeter/src/histogram.rs | 3 + oximeter/oximeter/src/types.rs | 15 +- sled-agent/Cargo.toml | 2 +- 15 files changed, 186 insertions(+), 205 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c2371a8c1..7ae80611d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -401,6 +401,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" + [[package]] name = "cookie" version = "0.16.0" @@ -2140,8 +2146,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openapi-lint" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/openapi-lint?branch=main#5ee546f7d5cdaf33fc355957b4decb792444292b" +source = "git+https://github.com/oxidecomputer/openapi-lint?branch=main#025fc867b7da62b33474d0a765823653a437f362" dependencies = [ + "convert_case 0.5.0", "indexmap", "openapiv3", ] @@ -2753,7 +2760,7 @@ version = "0.0.0" source = "git+https://github.com/oxidecomputer/progenitor#f1f9e2e93850713908f4e6494808a07f3b253108" dependencies = [ "anyhow", - "convert_case", + "convert_case 0.4.0", "getopts", "indexmap", "openapiv3", @@ -4195,7 +4202,7 @@ name = "typify-impl" version = "0.0.6-dev" source = "git+https://github.com/oxidecomputer/typify#9afa917671b29fc231bc9ce304e041bdd685af09" dependencies = [ - "convert_case", + "convert_case 0.4.0", "log", "proc-macro2", "quote", diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 10e7b30216..97494bdd67 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -605,7 +605,6 @@ where * Identity-related metadata that's included in nearly all public API objects */ #[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct IdentityMetadata { /** unique, immutable, system-controlled identifier for each resource */ pub id: Uuid, @@ -623,7 +622,6 @@ pub struct IdentityMetadata { * Create-time identity-related parameters */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct IdentityMetadataCreateParams { pub name: Name, pub description: String, @@ -633,7 +631,6 @@ pub struct IdentityMetadataCreateParams { * Updateable identity-related parameters */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct IdentityMetadataUpdateParams { pub name: Option, pub description: Option, @@ -665,7 +662,7 @@ pub struct IdentityMetadataUpdateParams { Serialize, JsonSchema, )] -#[serde(rename_all = "lowercase")] +#[serde(rename_all = "snake_case")] pub enum InstanceState { Creating, /* TODO-polish: paper over Creating in the API with Starting? */ Starting, @@ -772,7 +769,6 @@ impl From<&InstanceCpuCount> for i64 { * Client view of an [`InstanceRuntimeState`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct InstanceRuntimeState { pub run_state: InstanceState, pub time_run_state_updated: DateTime, @@ -793,7 +789,6 @@ impl From * Client view of an [`Instance`] */ #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct Instance { /* TODO is flattening here the intent in RFD 4? */ #[serde(flatten)] @@ -821,7 +816,6 @@ pub struct Instance { * Client view of an [`Disk`] */ #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct Disk { #[serde(flatten)] pub identity: IdentityMetadata, @@ -846,8 +840,7 @@ pub struct Disk { Serialize, JsonSchema, )] -#[serde(rename_all = "lowercase")] -#[serde(tag = "state", content = "instance")] +#[serde(tag = "state", content = "instance", rename_all = "snake_case")] pub enum DiskState { /** Disk is being initialized */ Creating, @@ -986,8 +979,7 @@ impl From for Saga { } #[derive(Clone, Debug, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "state")] +#[serde(tag = "state", rename_all = "snake_case")] pub enum SagaState { Running, Succeeded, @@ -995,8 +987,7 @@ pub enum SagaState { } #[derive(Clone, Debug, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "error")] +#[serde(tag = "error", rename_all = "snake_case")] pub enum SagaErrorInfo { ActionFailed { source_error: serde_json::Value }, DeserializeFailed { message: String }, @@ -1150,7 +1141,7 @@ impl JsonSchema for Ipv6Net { } #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "snake_case")] pub enum VpcRouterKind { System, Custom, @@ -1159,7 +1150,6 @@ pub enum VpcRouterKind { /// A VPC router defines a series of rules that indicate where traffic /// should be sent depending on its destination. #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct VpcRouter { /// common identifying metadata #[serde(flatten)] @@ -1197,8 +1187,7 @@ pub enum NetworkTarget { /// A subset of [`NetworkTarget`], `RouteTarget` specifies all /// possible targets that a route can forward to. #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "type", content = "value")] +#[serde(tag = "type", content = "value", rename_all = "snake_case")] pub enum RouteTarget { Ip(IpAddr), Vpc(Name), @@ -1270,8 +1259,7 @@ impl Display for RouteTarget { /// the kind of network traffic that will be matched to be forwarded /// to the [`RouteTarget`]. #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "type", content = "value")] +#[serde(tag = "type", content = "value", rename_all = "snake_case")] pub enum RouteDestination { Ip(IpAddr), Vpc(Name), @@ -1338,6 +1326,7 @@ impl Display for RouteDestination { Clone, Copy, Debug, PartialEq, Deserialize, Serialize, Display, JsonSchema, )] #[display("{}")] +#[serde(rename_all = "snake_case")] pub enum RouterRouteKind { /// Determines the default destination of traffic, such as whether it goes to the internet or not. /// @@ -1364,7 +1353,6 @@ pub enum RouterRouteKind { /// A route defines a rule that governs where traffic should be sent based on its destination. #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct RouterRoute { /// common identifying metadata #[serde(flatten)] @@ -1382,7 +1370,6 @@ pub struct RouterRoute { /// Create-time parameters for a [`RouterRoute`] #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct RouterRouteCreateParams { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, @@ -1392,7 +1379,6 @@ pub struct RouterRouteCreateParams { /// Updateable properties of a [`RouterRoute`] #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct RouterRouteUpdateParams { #[serde(flatten)] pub identity: IdentityMetadataUpdateParams, @@ -1523,21 +1509,21 @@ pub enum VpcFirewallRuleProtocol { } #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "snake_case")] pub enum VpcFirewallRuleStatus { Disabled, Enabled, } #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "snake_case")] pub enum VpcFirewallRuleDirection { Inbound, Outbound, } #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "snake_case")] pub enum VpcFirewallRuleAction { Allow, Deny, @@ -1546,8 +1532,7 @@ pub enum VpcFirewallRuleAction { /// A subset of [`NetworkTarget`], `VpcFirewallRuleTarget` specifies all /// possible targets that a firewall rule can be attached to. #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "type", content = "value")] +#[serde(tag = "type", content = "value", rename_all = "snake_case")] pub enum VpcFirewallRuleTarget { Vpc(Name), Subnet(Name), @@ -1617,8 +1602,7 @@ impl Display for VpcFirewallRuleTarget { /// A subset of [`NetworkTarget`], `VpcFirewallRuleHostFilter` specifies all /// possible targets that a route can forward to. #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "type", content = "value")] +#[serde(tag = "type", content = "value", rename_all = "snake_case")] pub enum VpcFirewallRuleHostFilter { Vpc(Name), Subnet(Name), @@ -1893,7 +1877,6 @@ impl JsonSchema for MacAddr { /// A `NetworkInterface` represents a virtual network interface device. #[derive(ObjectIdentity, Clone, Debug, Deserialize, JsonSchema, Serialize)] -#[serde(rename_all = "camelCase")] pub struct NetworkInterface { /// common identifying metadata #[serde(flatten)] diff --git a/nexus/Cargo.toml b/nexus/Cargo.toml index b24132958b..d4b49f513a 100644 --- a/nexus/Cargo.toml +++ b/nexus/Cargo.toml @@ -114,7 +114,7 @@ expectorate = "1.0.4" nexus-test-utils-macros = { path = "test-utils-macros" } nexus-test-utils = { path = "test-utils" } omicron-test-utils = { path = "../test-utils" } -openapiv3 = "1.0.0-beta.5" +openapiv3 = "1.0" subprocess = "0.2.8" [dev-dependencies.openapi-lint] diff --git a/nexus/src/external_api/console_api.rs b/nexus/src/external_api/console_api.rs index 61cb921573..2c9b09fd8e 100644 --- a/nexus/src/external_api/console_api.rs +++ b/nexus/src/external_api/console_api.rs @@ -34,7 +34,6 @@ use std::{collections::HashSet, ffi::OsString, path::PathBuf, sync::Arc}; use uuid::Uuid; #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct LoginParams { pub username: String, } diff --git a/nexus/src/external_api/params.rs b/nexus/src/external_api/params.rs index bc3d6796a5..8371cd31b4 100644 --- a/nexus/src/external_api/params.rs +++ b/nexus/src/external_api/params.rs @@ -22,7 +22,6 @@ use uuid::Uuid; * Create-time parameters for an [`Organization`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct OrganizationCreate { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, @@ -32,7 +31,6 @@ pub struct OrganizationCreate { * Updateable properties of an [`Organization`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct OrganizationUpdate { #[serde(flatten)] pub identity: IdentityMetadataUpdateParams, @@ -46,7 +44,6 @@ pub struct OrganizationUpdate { * Create-time parameters for a [`Project`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct ProjectCreate { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, @@ -56,7 +53,6 @@ pub struct ProjectCreate { * Updateable properties of a [`Project`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct ProjectUpdate { #[serde(flatten)] pub identity: IdentityMetadataUpdateParams, @@ -70,7 +66,6 @@ pub struct ProjectUpdate { * Create-time parameters for a [`NetworkInterface`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct NetworkInterfaceCreate { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, @@ -84,7 +79,6 @@ pub struct NetworkInterfaceCreate { * Create-time parameters for an [`Instance`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct InstanceCreate { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, @@ -101,7 +95,6 @@ pub struct InstanceCreate { * Create-time parameters for a [`Vpc`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct VpcCreate { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, @@ -112,7 +105,6 @@ pub struct VpcCreate { * Updateable properties of a [`Vpc`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct VpcUpdate { #[serde(flatten)] pub identity: IdentityMetadataUpdateParams, @@ -123,7 +115,6 @@ pub struct VpcUpdate { * Create-time parameters for a [`VpcSubnet`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct VpcSubnetCreate { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, @@ -135,7 +126,6 @@ pub struct VpcSubnetCreate { * Updateable properties of a [`VpcSubnet`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct VpcSubnetUpdate { #[serde(flatten)] pub identity: IdentityMetadataUpdateParams, @@ -149,7 +139,6 @@ pub struct VpcSubnetUpdate { /// Create-time parameters for a [`VpcRouter`] #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct VpcRouterCreate { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, @@ -157,7 +146,6 @@ pub struct VpcRouterCreate { /// Updateable properties of a [`VpcRouter`] #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct VpcRouterUpdate { #[serde(flatten)] pub identity: IdentityMetadataUpdateParams, @@ -171,7 +159,6 @@ pub struct VpcRouterUpdate { * Create-time parameters for a [`Disk`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct DiskCreate { /** common identifying metadata */ #[serde(flatten)] @@ -186,7 +173,6 @@ pub struct DiskCreate { * Parameters for the [`Disk`] to be attached or detached to an instance */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct DiskIdentifier { pub disk: Name, } @@ -203,7 +189,6 @@ pub struct DiskIdentifier { * Create-time parameters for a [`UserBuiltin`] */ #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct UserBuiltinCreate { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, diff --git a/nexus/src/external_api/views.rs b/nexus/src/external_api/views.rs index 8ae0e26a82..79ddadd326 100644 --- a/nexus/src/external_api/views.rs +++ b/nexus/src/external_api/views.rs @@ -26,7 +26,6 @@ use uuid::Uuid; * Client view of an [`Organization`] */ #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct Organization { #[serde(flatten)] pub identity: IdentityMetadata, @@ -46,7 +45,6 @@ impl Into for model::Organization { * Client view of a [`Project`] */ #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct Project { /* * TODO-correctness is flattening here (and in all the other types) the @@ -74,7 +72,6 @@ impl Into for model::Project { * Client view of a [`Vpc`] */ #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct Vpc { #[serde(flatten)] pub identity: IdentityMetadata, @@ -104,7 +101,6 @@ impl Into for model::Vpc { /// A VPC subnet represents a logical grouping for instances that allows network traffic between /// them, within a IPv4 subnetwork or optionall an IPv6 subnetwork. #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct VpcSubnet { /** common identifying metadata */ #[serde(flatten)] @@ -146,7 +142,6 @@ impl Into for model::VpcSubnet { * Client view of an [`Rack`] */ #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct Rack { #[serde(flatten)] pub identity: IdentityMetadata, @@ -166,7 +161,6 @@ impl Into for model::Rack { * Client view of an [`Sled`] */ #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct Sled { #[serde(flatten)] pub identity: IdentityMetadata, @@ -187,7 +181,6 @@ impl Into for model::Sled { * Client view of a [`User`] */ #[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct User { /* * TODO-correctness is flattening here (and in all the other types) the @@ -209,7 +202,6 @@ impl Into for model::UserBuiltin { // TODO: this may end up merged with User once more details about the user are // stored in the auth context. Right now there is only the ID. #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] pub struct SessionUser { pub id: Uuid, } @@ -228,7 +220,6 @@ impl Into for authn::Actor { * Client view of a [`Role`] */ #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase")] pub struct Role { pub name: RoleName, pub description: String, diff --git a/nexus/tests/integration_tests/vpc_subnets.rs b/nexus/tests/integration_tests/vpc_subnets.rs index 8e45e34997..e7f0c13cc2 100644 --- a/nexus/tests/integration_tests/vpc_subnets.rs +++ b/nexus/tests/integration_tests/vpc_subnets.rs @@ -96,7 +96,7 @@ async fn test_vpc_subnets(cptestctx: &ControlPlaneTestContext) { assert_put_400( client, &subnet_url, - String::from("{ \"ipv4Block\": \"2001:db8::0/96\" }"), + String::from("{ \"ipv4_block\": \"2001:db8::0/96\" }"), "unable to parse body: invalid address: 2001:db8::0", ) .await; @@ -105,7 +105,7 @@ async fn test_vpc_subnets(cptestctx: &ControlPlaneTestContext) { assert_put_400( client, &subnet_url, - String::from("{ \"ipv6Block\": \"10.1.9.32/16\" }"), + String::from("{ \"ipv6_block\": \"10.1.9.32/16\" }"), "unable to parse body: invalid address: 10.1.9.32", ) .await; diff --git a/openapi/nexus-internal.json b/openapi/nexus-internal.json index 7c300bd12d..c8f35a0cbe 100644 --- a/openapi/nexus-internal.json +++ b/openapi/nexus-internal.json @@ -98,10 +98,10 @@ "content": { "application/json": { "schema": { - "title": "Array_of_Result_of_Array_of_Sample_or_Error", + "title": "Array_of_ProducerResultsItem", "type": "array", "items": { - "$ref": "#/components/schemas/Result_of_Array_of_Sample_or_Error" + "$ref": "#/components/schemas/ProducerResultsItem" } } } @@ -288,7 +288,7 @@ }, "components": { "schemas": { - "BinRange_for_double": { + "BinRangedouble": { "description": "A type storing a range over `T`.\n\nThis type supports ranges similar to the `RangeTo`, `Range` and `RangeFrom` types in the standard library. Those cover `(..end)`, `(start..end)`, and `(start..)` respectively.", "oneOf": [ { @@ -348,7 +348,7 @@ } ] }, - "BinRange_for_int64": { + "BinRangeint64": { "description": "A type storing a range over `T`.\n\nThis type supports ranges similar to the `RangeTo`, `Range` and `RangeFrom` types in the standard library. Those cover `(..end)`, `(start..end)`, and `(start..)` respectively.", "oneOf": [ { @@ -408,7 +408,7 @@ } ] }, - "Bin_for_double": { + "Bindouble": { "description": "Type storing bin edges and a count of samples within it.", "type": "object", "properties": { @@ -422,7 +422,7 @@ "description": "The range of the support covered by this bin.", "allOf": [ { - "$ref": "#/components/schemas/BinRange_for_double" + "$ref": "#/components/schemas/BinRangedouble" } ] } @@ -432,7 +432,7 @@ "range" ] }, - "Bin_for_int64": { + "Binint64": { "description": "Type storing bin edges and a count of samples within it.", "type": "object", "properties": { @@ -446,7 +446,7 @@ "description": "The range of the support covered by this bin.", "allOf": [ { - "$ref": "#/components/schemas/BinRange_for_int64" + "$ref": "#/components/schemas/BinRangeint64" } ] } @@ -462,7 +462,7 @@ "format": "uint64", "minimum": 0 }, - "Cumulative_for_double": { + "Cumulativedouble": { "description": "A cumulative or counter data type.", "type": "object", "properties": { @@ -480,7 +480,7 @@ "value" ] }, - "Cumulative_for_int64": { + "Cumulativeint64": { "description": "A cumulative or counter data type.", "type": "object", "properties": { @@ -627,7 +627,7 @@ "type": "object", "properties": { "CumulativeI64": { - "$ref": "#/components/schemas/Cumulative_for_int64" + "$ref": "#/components/schemas/Cumulativeint64" } }, "required": [ @@ -639,7 +639,7 @@ "type": "object", "properties": { "CumulativeF64": { - "$ref": "#/components/schemas/Cumulative_for_double" + "$ref": "#/components/schemas/Cumulativedouble" } }, "required": [ @@ -651,7 +651,7 @@ "type": "object", "properties": { "HistogramI64": { - "$ref": "#/components/schemas/Histogram_for_int64" + "$ref": "#/components/schemas/Histogramint64" } }, "required": [ @@ -663,7 +663,7 @@ "type": "object", "properties": { "HistogramF64": { - "$ref": "#/components/schemas/Histogram_for_double" + "$ref": "#/components/schemas/Histogramdouble" } }, "required": [ @@ -1170,14 +1170,14 @@ } ] }, - "Histogram_for_double": { + "Histogramdouble": { "description": "A simple type for managing a histogram metric.\n\nA histogram maintains the count of any number of samples, over a set of bins. Bins are specified on construction via their _left_ edges, inclusive. There can't be any \"gaps\" in the bins, and an additional bin may be added to the left, right, or both so that the bins extend to the entire range of the support.\n\nNote that any gaps, unsorted bins, or non-finite values will result in an error.\n\nExample ------- ```rust use oximeter::histogram::{BinRange, Histogram};\n\nlet edges = [0i64, 10, 20]; let mut hist = Histogram::new(&edges).unwrap(); assert_eq!(hist.n_bins(), 4); // One additional bin for the range (20..) assert_eq!(hist.n_samples(), 0); hist.sample(4); hist.sample(100); assert_eq!(hist.n_samples(), 2);\n\nlet data = hist.iter().collect::>(); assert_eq!(data[0].range, BinRange::range(i64::MIN, 0)); // An additional bin for `..0` assert_eq!(data[0].count, 0); // Nothing is in this bin\n\nassert_eq!(data[1].range, BinRange::range(0, 10)); // The range `0..10` assert_eq!(data[1].count, 1); // 4 is sampled into this bin ```\n\nNotes -----\n\nHistograms may be constructed either from their left bin edges, or from a sequence of ranges. In either case, the left-most bin may be converted upon construction. In particular, if the left-most value is not equal to the minimum of the support, a new bin will be added from the minimum to that provided value. If the left-most value _is_ the support's minimum, because the provided bin was unbounded below, such as `(..0)`, then that bin will be converted into one bounded below, `(MIN..0)` in this case.\n\nThe short of this is that, most of the time, it shouldn't matter. If one specifies the extremes of the support as their bins, be aware that the left-most may be converted from a `BinRange::RangeTo` into a `BinRange::Range`. In other words, the first bin of a histogram is _always_ a `Bin::Range` or a `Bin::RangeFrom` after construction. In fact, every bin is one of those variants, the `BinRange::RangeTo` is only provided as a convenience during construction.", "type": "object", "properties": { "bins": { "type": "array", "items": { - "$ref": "#/components/schemas/Bin_for_double" + "$ref": "#/components/schemas/Bindouble" } }, "n_samples": { @@ -1196,14 +1196,14 @@ "start_time" ] }, - "Histogram_for_int64": { + "Histogramint64": { "description": "A simple type for managing a histogram metric.\n\nA histogram maintains the count of any number of samples, over a set of bins. Bins are specified on construction via their _left_ edges, inclusive. There can't be any \"gaps\" in the bins, and an additional bin may be added to the left, right, or both so that the bins extend to the entire range of the support.\n\nNote that any gaps, unsorted bins, or non-finite values will result in an error.\n\nExample ------- ```rust use oximeter::histogram::{BinRange, Histogram};\n\nlet edges = [0i64, 10, 20]; let mut hist = Histogram::new(&edges).unwrap(); assert_eq!(hist.n_bins(), 4); // One additional bin for the range (20..) assert_eq!(hist.n_samples(), 0); hist.sample(4); hist.sample(100); assert_eq!(hist.n_samples(), 2);\n\nlet data = hist.iter().collect::>(); assert_eq!(data[0].range, BinRange::range(i64::MIN, 0)); // An additional bin for `..0` assert_eq!(data[0].count, 0); // Nothing is in this bin\n\nassert_eq!(data[1].range, BinRange::range(0, 10)); // The range `0..10` assert_eq!(data[1].count, 1); // 4 is sampled into this bin ```\n\nNotes -----\n\nHistograms may be constructed either from their left bin edges, or from a sequence of ranges. In either case, the left-most bin may be converted upon construction. In particular, if the left-most value is not equal to the minimum of the support, a new bin will be added from the minimum to that provided value. If the left-most value _is_ the support's minimum, because the provided bin was unbounded below, such as `(..0)`, then that bin will be converted into one bounded below, `(MIN..0)` in this case.\n\nThe short of this is that, most of the time, it shouldn't matter. If one specifies the extremes of the support as their bins, be aware that the left-most may be converted from a `BinRange::RangeTo` into a `BinRange::Range`. In other words, the first bin of a histogram is _always_ a `Bin::Range` or a `Bin::RangeFrom` after construction. In fact, every bin is one of those variants, the `BinRange::RangeTo` is only provided as a convenience during construction.", "type": "object", "properties": { "bins": { "type": "array", "items": { - "$ref": "#/components/schemas/Bin_for_int64" + "$ref": "#/components/schemas/Binint64" } }, "n_samples": { @@ -1371,7 +1371,7 @@ "interval" ] }, - "Result_of_Array_of_Sample_or_Error": { + "ProducerResultsItem": { "oneOf": [ { "type": "object", @@ -1385,7 +1385,8 @@ }, "required": [ "Ok" - ] + ], + "additionalProperties": false }, { "type": "object", @@ -1396,7 +1397,8 @@ }, "required": [ "Err" - ] + ], + "additionalProperties": false } ] }, diff --git a/openapi/nexus.json b/openapi/nexus.json index 8b47a83ce2..9d7f2214c6 100644 --- a/openapi/nexus.json +++ b/openapi/nexus.json @@ -3210,7 +3210,7 @@ "description": "human-readable free-form text about a resource", "type": "string" }, - "devicePath": { + "device_path": { "type": "string" }, "id": { @@ -3226,14 +3226,14 @@ } ] }, - "projectId": { + "project_id": { "type": "string", "format": "uuid" }, "size": { "$ref": "#/components/schemas/ByteCount" }, - "snapshotId": { + "snapshot_id": { "nullable": true, "type": "string", "format": "uuid" @@ -3241,12 +3241,12 @@ "state": { "$ref": "#/components/schemas/DiskState" }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" @@ -3254,14 +3254,14 @@ }, "required": [ "description", - "devicePath", + "device_path", "id", "name", - "projectId", + "project_id", "size", "state", - "timeCreated", - "timeModified" + "time_created", + "time_modified" ] }, "DiskCreate": { @@ -3282,7 +3282,7 @@ } ] }, - "snapshotId": { + "snapshot_id": { "nullable": true, "description": "id for snapshot from which the Disk should be created, if any", "type": "string", @@ -3533,25 +3533,25 @@ } ] }, - "projectId": { + "project_id": { "description": "id for the project containing this Instance", "type": "string", "format": "uuid" }, - "runState": { + "run_state": { "$ref": "#/components/schemas/InstanceState" }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" }, - "timeRunStateUpdated": { + "time_run_state_updated": { "type": "string", "format": "date-time" } @@ -3563,11 +3563,11 @@ "memory", "name", "ncpus", - "projectId", - "runState", - "timeCreated", - "timeModified", - "timeRunStateUpdated" + "project_id", + "run_state", + "time_created", + "time_modified", + "time_run_state_updated" ] }, "InstanceCpuCount": { @@ -3701,7 +3701,7 @@ "type": "string", "format": "uuid" }, - "instanceId": { + "instance_id": { "description": "The Instance to which the interface belongs.", "type": "string", "format": "uuid" @@ -3727,22 +3727,22 @@ } ] }, - "subnetId": { + "subnet_id": { "description": "The subnet to which the interface belongs.", "type": "string", "format": "uuid" }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" }, - "vpcId": { + "vpc_id": { "description": "The VPC to which the interface belongs.", "type": "string", "format": "uuid" @@ -3751,14 +3751,14 @@ "required": [ "description", "id", - "instanceId", + "instance_id", "ip", "mac", "name", - "subnetId", - "timeCreated", - "timeModified", - "vpcId" + "subnet_id", + "time_created", + "time_modified", + "vpc_id" ] }, "NetworkInterfaceResultsPage": { @@ -3803,12 +3803,12 @@ } ] }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" @@ -3818,8 +3818,8 @@ "description", "id", "name", - "timeCreated", - "timeModified" + "time_created", + "time_modified" ] }, "OrganizationCreate": { @@ -3898,16 +3898,16 @@ } ] }, - "organizationId": { + "organization_id": { "type": "string", "format": "uuid" }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" @@ -3917,9 +3917,9 @@ "description", "id", "name", - "organizationId", - "timeCreated", - "timeModified" + "organization_id", + "time_created", + "time_modified" ] }, "ProjectCreate": { @@ -3998,12 +3998,12 @@ } ] }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" @@ -4013,8 +4013,8 @@ "description", "id", "name", - "timeCreated", - "timeModified" + "time_created", + "time_modified" ] }, "RackResultsPage": { @@ -4224,7 +4224,7 @@ "type": { "type": "string", "enum": [ - "internetGateway" + "internet_gateway" ] }, "value": { @@ -4270,7 +4270,7 @@ } ] }, - "routerId": { + "router_id": { "description": "The VPC Router to which the route belongs.", "type": "string", "format": "uuid" @@ -4278,12 +4278,12 @@ "target": { "$ref": "#/components/schemas/RouteTarget" }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" @@ -4295,10 +4295,10 @@ "id", "kind", "name", - "routerId", + "router_id", "target", - "timeCreated", - "timeModified" + "time_created", + "time_modified" ] }, "RouterRouteCreateParams": { @@ -4329,10 +4329,10 @@ "description": "The classification of a [`RouterRoute`] as defined by the system. The kind determines certain attributes such as if the route is modifiable and describes how or where the route was created.\n\nSee [RFD-21](https://rfd.shared.oxide.computer/rfd/0021#concept-router) for more context", "type": "string", "enum": [ - "Default", - "VpcSubnet", - "VpcPeering", - "Custom" + "default", + "vpc_subnet", + "vpc_peering", + "custom" ] }, "RouterRouteResultsPage": { @@ -4408,7 +4408,7 @@ "error": { "type": "string", "enum": [ - "actionFailed" + "action_failed" ] }, "source_error": {} @@ -4424,7 +4424,7 @@ "error": { "type": "string", "enum": [ - "deserializeFailed" + "deserialize_failed" ] }, "message": { @@ -4442,7 +4442,7 @@ "error": { "type": "string", "enum": [ - "injectedError" + "injected_error" ] } }, @@ -4456,7 +4456,7 @@ "error": { "type": "string", "enum": [ - "serializeFailed" + "serialize_failed" ] }, "message": { @@ -4474,7 +4474,7 @@ "error": { "type": "string", "enum": [ - "subsagaCreateFailed" + "subsaga_create_failed" ] }, "message": { @@ -4597,15 +4597,15 @@ } ] }, - "serviceAddress": { + "service_address": { "type": "string" }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" @@ -4615,9 +4615,9 @@ "description", "id", "name", - "serviceAddress", - "timeCreated", - "timeModified" + "service_address", + "time_created", + "time_modified" ] }, "SledResultsPage": { @@ -4717,12 +4717,12 @@ } ] }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" @@ -4732,8 +4732,8 @@ "description", "id", "name", - "timeCreated", - "timeModified" + "time_created", + "time_modified" ] }, "UserResultsPage": { @@ -4765,7 +4765,7 @@ "description": "human-readable free-form text about a resource", "type": "string" }, - "dnsName": { + "dns_name": { "description": "The name used for the VPC in DNS.", "allOf": [ { @@ -4786,22 +4786,22 @@ } ] }, - "projectId": { + "project_id": { "description": "id for the project containing this VPC", "type": "string", "format": "uuid" }, - "systemRouterId": { + "system_router_id": { "description": "id for the system router where subnet default routes are registered", "type": "string", "format": "uuid" }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" @@ -4809,13 +4809,13 @@ }, "required": [ "description", - "dnsName", + "dns_name", "id", "name", - "projectId", - "systemRouterId", - "timeCreated", - "timeModified" + "project_id", + "system_router_id", + "time_created", + "time_modified" ] }, "VpcCreate": { @@ -4825,7 +4825,7 @@ "description": { "type": "string" }, - "dnsName": { + "dns_name": { "$ref": "#/components/schemas/Name" }, "name": { @@ -4834,7 +4834,7 @@ }, "required": [ "description", - "dnsName", + "dns_name", "name" ] }, @@ -4904,12 +4904,12 @@ "$ref": "#/components/schemas/VpcFirewallRuleTarget" } }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" @@ -4925,8 +4925,8 @@ "priority", "status", "targets", - "timeCreated", - "timeModified" + "time_created", + "time_modified" ] }, "VpcFirewallRuleAction": { @@ -5055,7 +5055,7 @@ "type": { "type": "string", "enum": [ - "internetGateway" + "internet_gateway" ] }, "value": { @@ -5288,17 +5288,17 @@ } ] }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" }, - "vpcId": { + "vpc_id": { "description": "The VPC to which the router belongs.", "type": "string", "format": "uuid" @@ -5309,9 +5309,9 @@ "id", "kind", "name", - "timeCreated", - "timeModified", - "vpcId" + "time_created", + "time_modified", + "vpc_id" ] }, "VpcRouterCreate": { @@ -5389,7 +5389,7 @@ "type": "string", "format": "uuid" }, - "ipv4Block": { + "ipv4_block": { "nullable": true, "description": "The IPv4 subnet CIDR block.", "allOf": [ @@ -5398,7 +5398,7 @@ } ] }, - "ipv6Block": { + "ipv6_block": { "nullable": true, "description": "The IPv6 subnet CIDR block.", "allOf": [ @@ -5415,17 +5415,17 @@ } ] }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" }, - "vpcId": { + "vpc_id": { "description": "The VPC to which the subnet belongs.", "type": "string", "format": "uuid" @@ -5435,9 +5435,9 @@ "description", "id", "name", - "timeCreated", - "timeModified", - "vpcId" + "time_created", + "time_modified", + "vpc_id" ] }, "VpcSubnetCreate": { @@ -5447,7 +5447,7 @@ "description": { "type": "string" }, - "ipv4Block": { + "ipv4_block": { "nullable": true, "allOf": [ { @@ -5455,7 +5455,7 @@ } ] }, - "ipv6Block": { + "ipv6_block": { "nullable": true, "allOf": [ { @@ -5501,7 +5501,7 @@ "nullable": true, "type": "string" }, - "ipv4Block": { + "ipv4_block": { "nullable": true, "allOf": [ { @@ -5509,7 +5509,7 @@ } ] }, - "ipv6Block": { + "ipv6_block": { "nullable": true, "allOf": [ { @@ -5535,7 +5535,7 @@ "nullable": true, "type": "string" }, - "dnsName": { + "dns_name": { "nullable": true, "allOf": [ { diff --git a/openapi/sled-agent.json b/openapi/sled-agent.json index df605eac43..a2e6315339 100644 --- a/openapi/sled-agent.json +++ b/openapi/sled-agent.json @@ -535,7 +535,7 @@ "type": "string", "format": "uuid" }, - "instanceId": { + "instance_id": { "description": "The Instance to which the interface belongs.", "type": "string", "format": "uuid" @@ -561,22 +561,22 @@ } ] }, - "subnetId": { + "subnet_id": { "description": "The subnet to which the interface belongs.", "type": "string", "format": "uuid" }, - "timeCreated": { + "time_created": { "description": "timestamp when this resource was created", "type": "string", "format": "date-time" }, - "timeModified": { + "time_modified": { "description": "timestamp when this resource was last modified", "type": "string", "format": "date-time" }, - "vpcId": { + "vpc_id": { "description": "The VPC to which the interface belongs.", "type": "string", "format": "uuid" @@ -585,14 +585,14 @@ "required": [ "description", "id", - "instanceId", + "instance_id", "ip", "mac", "name", - "subnetId", - "timeCreated", - "timeModified", - "vpcId" + "subnet_id", + "time_created", + "time_modified", + "vpc_id" ] } } diff --git a/oximeter/collector/Cargo.toml b/oximeter/collector/Cargo.toml index 2a15b8b8e6..f471868095 100644 --- a/oximeter/collector/Cargo.toml +++ b/oximeter/collector/Cargo.toml @@ -24,7 +24,7 @@ uuid = { version = "0.8.2", features = [ "v4", "serde" ] } [dev-dependencies] expectorate = "1.0.4" omicron-test-utils = { path = "../../test-utils" } -openapiv3 = "1.0.0-beta.5" +openapiv3 = "1.0" serde_json = "1.0.74" subprocess = "0.2.8" diff --git a/oximeter/collector/src/lib.rs b/oximeter/collector/src/lib.rs index 1e152d45c5..3f24d28d87 100644 --- a/oximeter/collector/src/lib.rs +++ b/oximeter/collector/src/lib.rs @@ -13,7 +13,7 @@ use dropshot::{ }; use omicron_common::api::internal::nexus::ProducerEndpoint; use omicron_common::backoff; -use oximeter::types::ProducerResults; +use oximeter::types::{ProducerResults, ProducerResultsItem}; use oximeter_db::{Client, DbWrite}; use serde::{Deserialize, Serialize}; use slog::{debug, error, info, o, trace, warn, Drain, Logger}; @@ -184,8 +184,8 @@ async fn results_sink( let mut flattened = Vec::with_capacity(results.len()); for inner_batch in results.into_iter() { match inner_batch { - Ok(samples) => flattened.extend(samples.into_iter()), - Err(e) => { + ProducerResultsItem::Ok(samples) => flattened.extend(samples.into_iter()), + ProducerResultsItem::Err(e) => { debug!( log, "received error (not samples) from a producer: {}", diff --git a/oximeter/oximeter/src/histogram.rs b/oximeter/oximeter/src/histogram.rs index 5a865b67ee..075e9818f4 100644 --- a/oximeter/oximeter/src/histogram.rs +++ b/oximeter/oximeter/src/histogram.rs @@ -73,6 +73,7 @@ pub enum HistogramError { /// This type supports ranges similar to the `RangeTo`, `Range` and `RangeFrom` types in the /// standard library. Those cover `(..end)`, `(start..end)`, and `(start..)` respectively. #[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize, JsonSchema)] +#[schemars(rename = "BinRange{T}")] pub enum BinRange { /// A range unbounded below and exclusively above, `..end`. RangeTo(T), @@ -180,6 +181,7 @@ where /// Type storing bin edges and a count of samples within it. #[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize, JsonSchema)] +#[schemars(rename = "Bin{T}")] pub struct Bin { /// The range of the support covered by this bin. pub range: BinRange, @@ -234,6 +236,7 @@ pub struct Bin { /// _always_ a `Bin::Range` or a `Bin::RangeFrom` after construction. In fact, every bin is one of /// those variants, the `BinRange::RangeTo` is only provided as a convenience during construction. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[schemars(rename = "Histogram{T}")] pub struct Histogram { start_time: DateTime, bins: Vec>, diff --git a/oximeter/oximeter/src/types.rs b/oximeter/oximeter/src/types.rs index 6de32fb5c6..efaa44de01 100644 --- a/oximeter/oximeter/src/types.rs +++ b/oximeter/oximeter/src/types.rs @@ -405,6 +405,7 @@ pub enum Error { /// A cumulative or counter data type. #[derive(Debug, Clone, Copy, PartialEq, JsonSchema, Deserialize, Serialize)] +#[schemars(rename = "Cumulative{T}")] pub struct Cumulative { start_time: DateTime, value: T, @@ -573,7 +574,12 @@ impl Sample { } type ProducerList = Vec>; -pub type ProducerResults = Vec, Error>>; +#[derive(Debug, Clone, JsonSchema, Deserialize, Serialize)] +pub enum ProducerResultsItem { + Ok(Vec), + Err(Error), +} +pub type ProducerResults = Vec; /// The `ProducerRegistry` is a centralized collection point for metrics in consumer code. #[derive(Debug, Clone)] @@ -617,7 +623,12 @@ impl ProducerRegistry { let mut producers = self.producers.lock().unwrap(); let mut results = Vec::with_capacity(producers.len()); for producer in producers.iter_mut() { - results.push(producer.produce().map(|samples| samples.collect())); + results.push( + producer.produce().map(Iterator::collect).map_or_else( + ProducerResultsItem::Err, + ProducerResultsItem::Ok, + ), + ); } results } diff --git a/sled-agent/Cargo.toml b/sled-agent/Cargo.toml index 61241d3bb0..8b894f63e3 100644 --- a/sled-agent/Cargo.toml +++ b/sled-agent/Cargo.toml @@ -46,7 +46,7 @@ expectorate = "1.0.4" mockall = "0.11" omicron-test-utils = { path = "../test-utils" } openapi-lint = { git = "https://github.com/oxidecomputer/openapi-lint", branch = "main" } -openapiv3 = "1.0.0-beta.5" +openapiv3 = "1.0" serial_test = "0.5" subprocess = "0.2.8" slog-async = "2.6"