diff --git a/Cargo.lock b/Cargo.lock index 3cdf3dd678..85e42458d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7245,9 +7245,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.13" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" dependencies = [ "bytes", "chrono", @@ -7260,9 +7260,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.13" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index d4f81b0310..f7256ce8b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -314,7 +314,7 @@ rustfmt-wrapper = "0.2" rustls = "0.21.9" rustyline = "12.0.0" samael = { git = "https://github.com/njaremko/samael", features = ["xmlsec"], branch = "master" } -schemars = "0.8.12" +schemars = "0.8.16" secrecy = "0.8.0" semver = { version = "1.0.20", features = ["std", "serde"] } serde = { version = "1.0", default-features = false, features = [ "derive" ] } diff --git a/nexus/db-queries/src/db/datastore/switch_port.rs b/nexus/db-queries/src/db/datastore/switch_port.rs index 221feee23c..4771768e43 100644 --- a/nexus/db-queries/src/db/datastore/switch_port.rs +++ b/nexus/db-queries/src/db/datastore/switch_port.rs @@ -1196,7 +1196,7 @@ mod test { use nexus_test_utils::db::test_setup_database; use nexus_types::external_api::params::{ BgpAnnounceSetCreate, BgpConfigCreate, BgpPeer, BgpPeerConfig, - SwitchPortConfig, SwitchPortGeometry, SwitchPortSettingsCreate, + SwitchPortConfigCreate, SwitchPortGeometry, SwitchPortSettingsCreate, }; use omicron_common::api::external::{ IdentityMetadataCreateParams, Name, NameOrId, @@ -1250,7 +1250,7 @@ mod test { name: "test-settings".parse().unwrap(), description: "test settings".into(), }, - port_config: SwitchPortConfig { + port_config: SwitchPortConfigCreate { geometry: SwitchPortGeometry::Qsfp28x1, }, groups: Vec::new(), diff --git a/nexus/src/app/rack.rs b/nexus/src/app/rack.rs index a0dcb7fcb1..23ee39415f 100644 --- a/nexus/src/app/rack.rs +++ b/nexus/src/app/rack.rs @@ -27,10 +27,10 @@ use nexus_types::external_api::params::BgpAnnounceSetCreate; use nexus_types::external_api::params::BgpAnnouncementCreate; use nexus_types::external_api::params::BgpConfigCreate; use nexus_types::external_api::params::BgpPeer; -use nexus_types::external_api::params::LinkConfig; -use nexus_types::external_api::params::LldpServiceConfig; +use nexus_types::external_api::params::LinkConfigCreate; +use nexus_types::external_api::params::LldpServiceConfigCreate; use nexus_types::external_api::params::RouteConfig; -use nexus_types::external_api::params::SwitchPortConfig; +use nexus_types::external_api::params::SwitchPortConfigCreate; use nexus_types::external_api::params::UninitializedSledId; use nexus_types::external_api::params::{ AddressLotCreate, BgpPeerConfig, LoopbackAddressCreate, Route, SiloCreate, @@ -587,7 +587,7 @@ impl super::Nexus { description: "initial uplink configuration".to_string(), }; - let port_config = SwitchPortConfig { + let port_config = SwitchPortConfigCreate { geometry: nexus_types::external_api::params::SwitchPortGeometry::Qsfp28x1, }; @@ -653,9 +653,9 @@ impl super::Nexus { .bgp_peers .insert("phy0".to_string(), BgpPeerConfig { peers }); - let link = LinkConfig { + let link = LinkConfigCreate { mtu: 1500, //TODO https://github.com/oxidecomputer/omicron/issues/2274 - lldp: LldpServiceConfig { + lldp: LldpServiceConfigCreate { enabled: false, lldp_config: None, }, diff --git a/nexus/tests/integration_tests/switch_port.rs b/nexus/tests/integration_tests/switch_port.rs index df4d96c6d1..c6e774be09 100644 --- a/nexus/tests/integration_tests/switch_port.rs +++ b/nexus/tests/integration_tests/switch_port.rs @@ -11,9 +11,9 @@ use nexus_test_utils_macros::nexus_test; use nexus_types::external_api::params::{ Address, AddressConfig, AddressLotBlockCreate, AddressLotCreate, BgpAnnounceSetCreate, BgpAnnouncementCreate, BgpConfigCreate, BgpPeer, - BgpPeerConfig, LinkConfig, LinkFec, LinkSpeed, LldpServiceConfig, Route, - RouteConfig, SwitchInterfaceConfig, SwitchInterfaceKind, - SwitchPortApplySettings, SwitchPortSettingsCreate, + BgpPeerConfig, LinkConfigCreate, LinkFec, LinkSpeed, + LldpServiceConfigCreate, Route, RouteConfig, SwitchInterfaceConfigCreate, + SwitchInterfaceKind, SwitchPortApplySettings, SwitchPortSettingsCreate, }; use nexus_types::external_api::views::Rack; use omicron_common::api::external::{ @@ -113,9 +113,9 @@ async fn test_port_settings_basic_crud(ctx: &ControlPlaneTestContext) { // links settings.links.insert( "phy0".into(), - LinkConfig { + LinkConfigCreate { mtu: 4700, - lldp: LldpServiceConfig { enabled: false, lldp_config: None }, + lldp: LldpServiceConfigCreate { enabled: false, lldp_config: None }, fec: LinkFec::None, speed: LinkSpeed::Speed100G, autoneg: false, @@ -124,7 +124,7 @@ async fn test_port_settings_basic_crud(ctx: &ControlPlaneTestContext) { // interfaces settings.interfaces.insert( "phy0".into(), - SwitchInterfaceConfig { + SwitchInterfaceConfigCreate { v6_enabled: true, kind: SwitchInterfaceKind::Primary, }, diff --git a/nexus/types/src/external_api/params.rs b/nexus/types/src/external_api/params.rs index 6749794a9a..209d1f607c 100644 --- a/nexus/types/src/external_api/params.rs +++ b/nexus/types/src/external_api/params.rs @@ -1387,14 +1387,14 @@ pub struct SwtichPortSettingsGroupCreate { pub struct SwitchPortSettingsCreate { #[serde(flatten)] pub identity: IdentityMetadataCreateParams, - pub port_config: SwitchPortConfig, + pub port_config: SwitchPortConfigCreate, pub groups: Vec, /// Links indexed by phy name. On ports that are not broken out, this is /// always phy0. On a 2x breakout the options are phy0 and phy1, on 4x /// phy0-phy3, etc. - pub links: HashMap, + pub links: HashMap, /// Interfaces indexed by link name. - pub interfaces: HashMap, + pub interfaces: HashMap, /// Routes indexed by interface name. pub routes: HashMap, /// BGP peers indexed by interface name. @@ -1407,7 +1407,7 @@ impl SwitchPortSettingsCreate { pub fn new(identity: IdentityMetadataCreateParams) -> Self { Self { identity, - port_config: SwitchPortConfig { + port_config: SwitchPortConfigCreate { geometry: SwitchPortGeometry::Qsfp28x1, }, groups: Vec::new(), @@ -1423,7 +1423,7 @@ impl SwitchPortSettingsCreate { /// Physical switch port configuration. #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] #[serde(rename_all = "snake_case")] -pub struct SwitchPortConfig { +pub struct SwitchPortConfigCreate { /// Link geometry for the switch port. pub geometry: SwitchPortGeometry, } @@ -1526,12 +1526,12 @@ impl From for LinkSpeed { /// Switch link configuration. #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct LinkConfig { +pub struct LinkConfigCreate { /// Maximum transmission unit for the link. pub mtu: u16, /// The link-layer discovery protocol (LLDP) configuration for the link. - pub lldp: LldpServiceConfig, + pub lldp: LldpServiceConfigCreate, /// The forward error correction mode of the link. pub fec: LinkFec, @@ -1546,7 +1546,7 @@ pub struct LinkConfig { /// The LLDP configuration associated with a port. LLDP may be either enabled or /// disabled, if enabled, an LLDP configuration must be provided by name or id. #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct LldpServiceConfig { +pub struct LldpServiceConfigCreate { /// Whether or not LLDP is enabled. pub enabled: bool, @@ -1558,7 +1558,7 @@ pub struct LldpServiceConfig { /// A layer-3 switch interface configuration. When IPv6 is enabled, a link local /// address will be created for the interface. #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct SwitchInterfaceConfig { +pub struct SwitchInterfaceConfigCreate { /// Whether or not IPv6 is enabled. pub v6_enabled: bool, diff --git a/openapi/nexus.json b/openapi/nexus.json index 815cc399ae..3b8b3525dc 100644 --- a/openapi/nexus.json +++ b/openapi/nexus.json @@ -12496,7 +12496,7 @@ "minLength": 1, "maxLength": 11 }, - "LinkConfig": { + "LinkConfigCreate": { "description": "Switch link configuration.", "type": "object", "properties": { @@ -12516,7 +12516,7 @@ "description": "The link-layer discovery protocol (LLDP) configuration for the link.", "allOf": [ { - "$ref": "#/components/schemas/LldpServiceConfig" + "$ref": "#/components/schemas/LldpServiceConfigCreate" } ] }, @@ -12638,6 +12638,31 @@ ] }, "LldpServiceConfig": { + "description": "A link layer discovery protocol (LLDP) service configuration.", + "type": "object", + "properties": { + "enabled": { + "description": "Whether or not the LLDP service is enabled.", + "type": "boolean" + }, + "id": { + "description": "The id of this LLDP service instance.", + "type": "string", + "format": "uuid" + }, + "lldp_config_id": { + "nullable": true, + "description": "The link-layer discovery protocol configuration for this service.", + "type": "string", + "format": "uuid" + } + }, + "required": [ + "enabled", + "id" + ] + }, + "LldpServiceConfigCreate": { "description": "The LLDP configuration associated with a port. LLDP may be either enabled or disabled, if enabled, an LLDP configuration must be provided by name or id.", "type": "object", "properties": { @@ -14251,6 +14276,45 @@ ] }, "SwitchInterfaceConfig": { + "description": "A switch port interface configuration for a port settings object.", + "type": "object", + "properties": { + "id": { + "description": "A unique identifier for this switch interface.", + "type": "string", + "format": "uuid" + }, + "interface_name": { + "description": "The name of this switch interface.", + "type": "string" + }, + "kind": { + "description": "The switch interface kind.", + "allOf": [ + { + "$ref": "#/components/schemas/SwitchInterfaceKind2" + } + ] + }, + "port_settings_id": { + "description": "The port settings object this switch interface configuration belongs to.", + "type": "string", + "format": "uuid" + }, + "v6_enabled": { + "description": "Whether or not IPv6 is enabled on this interface.", + "type": "boolean" + } + }, + "required": [ + "id", + "interface_name", + "kind", + "port_settings_id", + "v6_enabled" + ] + }, + "SwitchInterfaceConfigCreate": { "description": "A layer-3 switch interface configuration. When IPv6 is enabled, a link local address will be created for the interface.", "type": "object", "properties": { @@ -14329,6 +14393,32 @@ } ] }, + "SwitchInterfaceKind2": { + "description": "Describes the kind of an switch interface.", + "oneOf": [ + { + "description": "Primary interfaces are associated with physical links. There is exactly one primary interface per physical link.", + "type": "string", + "enum": [ + "primary" + ] + }, + { + "description": "VLAN interfaces allow physical interfaces to be multiplexed onto multiple logical links, each distinguished by a 12-bit 802.1Q Ethernet tag.", + "type": "string", + "enum": [ + "vlan" + ] + }, + { + "description": "Loopback interfaces are anchors for IP addresses that are not specific to any particular port.", + "type": "string", + "enum": [ + "loopback" + ] + } + ] + }, "SwitchLocation": { "description": "Identifies switch physical location", "oneOf": [ @@ -14467,6 +14557,29 @@ ] }, "SwitchPortConfig": { + "description": "A physical port configuration for a port settings object.", + "type": "object", + "properties": { + "geometry": { + "description": "The physical link geometry of the port.", + "allOf": [ + { + "$ref": "#/components/schemas/SwitchPortGeometry2" + } + ] + }, + "port_settings_id": { + "description": "The id of the port settings object this configuration belongs to.", + "type": "string", + "format": "uuid" + } + }, + "required": [ + "geometry", + "port_settings_id" + ] + }, + "SwitchPortConfigCreate": { "description": "Physical switch port configuration.", "type": "object", "properties": { @@ -14509,6 +14622,32 @@ } ] }, + "SwitchPortGeometry2": { + "description": "The link geometry associated with a switch port.", + "oneOf": [ + { + "description": "The port contains a single QSFP28 link with four lanes.", + "type": "string", + "enum": [ + "qsfp28x1" + ] + }, + { + "description": "The port contains two QSFP28 links each with two lanes.", + "type": "string", + "enum": [ + "qsfp28x2" + ] + }, + { + "description": "The port contains four SFP28 links each with one lane.", + "type": "string", + "enum": [ + "sfp28x4" + ] + } + ] + }, "SwitchPortLinkConfig": { "description": "A link configuration for a port settings object.", "type": "object", @@ -14677,21 +14816,21 @@ "description": "Interfaces indexed by link name.", "type": "object", "additionalProperties": { - "$ref": "#/components/schemas/SwitchInterfaceConfig" + "$ref": "#/components/schemas/SwitchInterfaceConfigCreate" } }, "links": { "description": "Links indexed by phy name. On ports that are not broken out, this is always phy0. On a 2x breakout the options are phy0 and phy1, on 4x phy0-phy3, etc.", "type": "object", "additionalProperties": { - "$ref": "#/components/schemas/LinkConfig" + "$ref": "#/components/schemas/LinkConfigCreate" } }, "name": { "$ref": "#/components/schemas/Name" }, "port_config": { - "$ref": "#/components/schemas/SwitchPortConfig" + "$ref": "#/components/schemas/SwitchPortConfigCreate" }, "routes": { "description": "Routes indexed by interface name.", diff --git a/workspace-hack/Cargo.toml b/workspace-hack/Cargo.toml index 8998f7594b..653e8b370a 100644 --- a/workspace-hack/Cargo.toml +++ b/workspace-hack/Cargo.toml @@ -85,7 +85,7 @@ regex-automata = { version = "0.4.3", default-features = false, features = ["dfa regex-syntax = { version = "0.8.2" } reqwest = { version = "0.11.22", features = ["blocking", "json", "rustls-tls", "stream"] } ring = { version = "0.17.7", features = ["std"] } -schemars = { version = "0.8.13", features = ["bytes", "chrono", "uuid1"] } +schemars = { version = "0.8.16", features = ["bytes", "chrono", "uuid1"] } semver = { version = "1.0.20", features = ["serde"] } serde = { version = "1.0.193", features = ["alloc", "derive", "rc"] } serde_json = { version = "1.0.108", features = ["raw_value", "unbounded_depth"] } @@ -188,7 +188,7 @@ regex-automata = { version = "0.4.3", default-features = false, features = ["dfa regex-syntax = { version = "0.8.2" } reqwest = { version = "0.11.22", features = ["blocking", "json", "rustls-tls", "stream"] } ring = { version = "0.17.7", features = ["std"] } -schemars = { version = "0.8.13", features = ["bytes", "chrono", "uuid1"] } +schemars = { version = "0.8.16", features = ["bytes", "chrono", "uuid1"] } semver = { version = "1.0.20", features = ["serde"] } serde = { version = "1.0.193", features = ["alloc", "derive", "rc"] } serde_json = { version = "1.0.108", features = ["raw_value", "unbounded_depth"] }