diff --git a/Cargo.lock b/Cargo.lock index 89ae56e6..51863187 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,7 +121,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure", ] @@ -133,7 +133,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -201,7 +201,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -212,7 +212,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -457,7 +457,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -688,7 +688,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -699,7 +699,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -751,7 +751,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -772,7 +772,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -859,7 +859,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -933,7 +933,7 @@ dependencies = [ "semver", "serde", "serde_tokenstream", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1226,7 +1226,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1786,7 +1786,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1906,7 +1906,7 @@ checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2277,7 +2277,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2393,7 +2393,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2643,7 +2643,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2696,7 +2696,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2807,9 +2807,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" dependencies = [ "unicode-ident", ] @@ -2817,7 +2817,7 @@ dependencies = [ [[package]] name = "progenitor" version = "0.11.2" -source = "git+https://github.com/oxidecomputer/progenitor#4c06c8c01e23f5092c97ab95b8359ae2511316a2" +source = "git+https://github.com/oxidecomputer/progenitor#7debfcfacad23bbd54a9386295ab95eaf0a33e72" dependencies = [ "progenitor-impl", ] @@ -2840,7 +2840,7 @@ dependencies = [ [[package]] name = "progenitor-impl" version = "0.11.2" -source = "git+https://github.com/oxidecomputer/progenitor#4c06c8c01e23f5092c97ab95b8359ae2511316a2" +source = "git+https://github.com/oxidecomputer/progenitor#7debfcfacad23bbd54a9386295ab95eaf0a33e72" dependencies = [ "heck", "http 1.4.0", @@ -2852,7 +2852,7 @@ dependencies = [ "schemars", "serde", "serde_json", - "syn 2.0.111", + "syn 2.0.114", "thiserror 2.0.17", "typify", "unicode-ident", @@ -3423,7 +3423,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3492,7 +3492,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3503,7 +3503,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3567,7 +3567,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3831,7 +3831,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3843,7 +3843,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3881,9 +3881,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -3907,7 +3907,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4105,7 +4105,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4116,7 +4116,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4228,7 +4228,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4458,7 +4458,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4569,7 +4569,7 @@ dependencies = [ "semver", "serde", "serde_json", - "syn 2.0.111", + "syn 2.0.114", "thiserror 2.0.17", "unicode-ident", ] @@ -4587,7 +4587,7 @@ dependencies = [ "serde", "serde_json", "serde_tokenstream", - "syn 2.0.111", + "syn 2.0.114", "typify-impl", ] @@ -4800,7 +4800,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "wasm-bindgen-shared", ] @@ -4835,7 +4835,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5015,7 +5015,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5026,7 +5026,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5325,7 +5325,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure", ] @@ -5346,7 +5346,7 @@ checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5366,7 +5366,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure", ] @@ -5406,7 +5406,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] diff --git a/cli/docs/cli.json b/cli/docs/cli.json index b5ea750b..f8fb38a5 100644 --- a/cli/docs/cli.json +++ b/cli/docs/cli.json @@ -1708,16 +1708,32 @@ "subcommands": [ { "name": "join", - "about": "Join multicast group.", - "long_about": "This is functionally equivalent to adding the instance via the group's member management endpoint or updating the instance's `multicast_groups` field. All approaches modify the same membership and trigger reconciliation.", + "about": "Join a multicast group.", + "long_about": "This is functionally equivalent to adding the instance via the group's member management endpoint or updating the instance's `multicast_groups` field. All approaches modify the same membership and trigger reconciliation.\n\nAuthorization: requires Modify on the instance identified in the URL path (checked first) and Read on the multicast group. Checking instance permission first prevents creating orphaned groups when the instance check fails.\n\nGroup Identification: Groups can be referenced by name, IP address, or UUID. All three are fleet-wide unique identifiers: - By name: If group doesn't exist, it's implicitly created with an auto-allocated IP from a multicast pool linked to the caller's silo. Pool selection prefers the default pool; if none, selects alphabetically. - By IP: If group doesn't exist, it's implicitly created using that IP. The pool is determined by which pool contains the IP. - By UUID: Group must already exist.\n\nSource IP filtering: - Duplicate IPs in the request are automatically deduplicated. - Maximum of 64 source IPs allowed (per RFC 3376, IGMPv3). - ASM: Sources are optional. Providing sources enables source filtering via IGMPv3/MLDv2 even for ASM addresses. - SSM: Sources are required. SSM addresses (232.0.0.0/8 for IPv4, ff3x::/32 for IPv6) must have at least one source specified.", "args": [ { "long": "instance", "help": "Name or ID of the instance" }, + { + "long": "ip-version", + "values": [ + "v4", + "v6" + ], + "help": "IP version for pool selection when creating a group by name. Required if both IPv4 and IPv6 default multicast pools are linked." + }, + { + "long": "json-body", + "help": "Path to a file that contains the full json body." + }, + { + "long": "json-body-template", + "help": "XXX" + }, { "long": "multicast-group", - "help": "Name or ID of the multicast group" + "help": "Name, ID, or IP address of the multicast group" }, { "long": "profile", @@ -1732,8 +1748,8 @@ }, { "name": "leave", - "about": "Leave multicast group.", - "long_about": "This is functionally equivalent to removing the instance via the group's member management endpoint or updating the instance's `multicast_groups` field. All approaches modify the same membership and trigger reconciliation.", + "about": "Leave a multicast group.", + "long_about": "The group can be specified by name, UUID, or multicast IP address. All three are fleet-wide unique identifiers.\n\nThis is functionally equivalent to removing the instance via the group's member management endpoint or updating the instance's `multicast_groups` field. All approaches modify the same membership and trigger reconciliation.\n\nAuthorization: requires Modify on the instance (checked first) and Read on the multicast group.", "args": [ { "long": "instance", @@ -1741,7 +1757,7 @@ }, { "long": "multicast-group", - "help": "Name or ID of the multicast group" + "help": "Name, ID, or IP address of the multicast group" }, { "long": "profile", @@ -1756,12 +1772,16 @@ }, { "name": "list", - "about": "List multicast groups for instance", + "about": "List multicast groups for an instance.", "args": [ { "long": "instance", "help": "Name or ID of the instance" }, + { + "long": "limit", + "help": "Maximum number of items returned by a single call" + }, { "long": "profile", "help": "Configuration profile to use for commands", @@ -1770,6 +1790,12 @@ { "long": "project", "help": "Name or ID of the project" + }, + { + "long": "sort-by", + "values": [ + "id_ascending" + ] } ] } @@ -1787,62 +1813,9 @@ } ], "subcommands": [ - { - "name": "create", - "about": "Create a multicast group.", - "long_about": "Multicast groups are fleet-scoped resources that can be joined by instances across projects and silos. A single multicast IP serves all group members regardless of project or silo boundaries.", - "args": [ - { - "long": "description" - }, - { - "long": "json-body", - "help": "Path to a file that contains the full json body." - }, - { - "long": "json-body-template", - "help": "XXX" - }, - { - "long": "multicast-ip", - "help": "The multicast IP address to allocate. If None, one will be allocated from the default pool." - }, - { - "long": "mvlan", - "help": "Multicast VLAN (MVLAN) for egress multicast traffic to upstream networks. Tags packets leaving the rack to traverse VLAN-segmented upstream networks.\n\nValid range: 2-4094 (VLAN IDs 0-1 are reserved by IEEE 802.1Q standard)." - }, - { - "long": "name" - }, - { - "long": "pool", - "help": "Name or ID of the IP pool to allocate from. If None, uses the default multicast pool." - }, - { - "long": "profile", - "help": "Configuration profile to use for commands", - "global": true - } - ] - }, - { - "name": "delete", - "about": "Delete a multicast group.", - "args": [ - { - "long": "multicast-group", - "help": "Name or ID of the multicast group" - }, - { - "long": "profile", - "help": "Configuration profile to use for commands", - "global": true - } - ] - }, { "name": "list", - "about": "List all multicast groups.", + "about": "List multicast groups.", "args": [ { "long": "limit", @@ -1863,21 +1836,6 @@ } ] }, - { - "name": "lookup-by-ip", - "about": "Look up multicast group by IP address.", - "args": [ - { - "long": "address", - "help": "IP address of the multicast group" - }, - { - "long": "profile", - "help": "Configuration profile to use for commands", - "global": true - } - ] - }, { "name": "member", "args": [ @@ -1888,41 +1846,10 @@ } ], "subcommands": [ - { - "name": "add", - "about": "Add instance to a multicast group.", - "long_about": "Functionally equivalent to updating the instance's `multicast_groups` field. Both approaches modify the same underlying membership and trigger the same reconciliation logic.\n\nSpecify instance by name (requires `?project=`) or UUID.", - "args": [ - { - "long": "instance", - "help": "Name or ID of the instance to add to the multicast group" - }, - { - "long": "json-body", - "help": "Path to a file that contains the full json body." - }, - { - "long": "json-body-template", - "help": "XXX" - }, - { - "long": "multicast-group", - "help": "Name or ID of the multicast group" - }, - { - "long": "profile", - "help": "Configuration profile to use for commands", - "global": true - }, - { - "long": "project", - "help": "Name or ID of the project" - } - ] - }, { "name": "list", "about": "List members of a multicast group.", + "long_about": "The group can be specified by name, UUID, or multicast IP address.", "args": [ { "long": "limit", @@ -1930,7 +1857,7 @@ }, { "long": "multicast-group", - "help": "Name or ID of the multicast group" + "help": "Name, ID, or IP address of the multicast group" }, { "long": "profile", @@ -1944,73 +1871,17 @@ ] } ] - }, - { - "name": "remove", - "about": "Remove instance from a multicast group.", - "long_about": "Functionally equivalent to removing the group from the instance's `multicast_groups` field. Both approaches modify the same underlying membership and trigger reconciliation.\n\nSpecify instance by name (requires `?project=`) or UUID.", - "args": [ - { - "long": "instance", - "help": "Name or ID of the instance" - }, - { - "long": "multicast-group", - "help": "Name or ID of the multicast group" - }, - { - "long": "profile", - "help": "Configuration profile to use for commands", - "global": true - }, - { - "long": "project", - "help": "Name or ID of the project" - } - ] - } - ] - }, - { - "name": "update", - "about": "Update a multicast group.", - "args": [ - { - "long": "description" - }, - { - "long": "json-body", - "help": "Path to a file that contains the full json body." - }, - { - "long": "json-body-template", - "help": "XXX" - }, - { - "long": "multicast-group", - "help": "Name or ID of the multicast group" - }, - { - "long": "mvlan", - "help": "Multicast VLAN (MVLAN) for egress multicast traffic to upstream networks. Set to null to clear the MVLAN. Valid range: 2-4094 when provided. Omit the field to leave mvlan unchanged." - }, - { - "long": "name" - }, - { - "long": "profile", - "help": "Configuration profile to use for commands", - "global": true } ] }, { "name": "view", "about": "Fetch a multicast group.", + "long_about": "The group can be specified by name, UUID, or multicast IP address. (e.g., \"224.1.2.3\" or \"ff38::1\").", "args": [ { "long": "multicast-group", - "help": "Name or ID of the multicast group" + "help": "Name, ID, or IP address of the multicast group" }, { "long": "profile", @@ -2048,9 +1919,6 @@ { "long": "description" }, - { - "long": "ip-pool" - }, { "long": "json-body", "help": "Path to a file that contains the full json body." @@ -2326,18 +2194,6 @@ { "long": "description" }, - { - "long": "ip", - "help": "An IP address to reserve for use as a floating IP. This field is optional: when not set, an address will be automatically chosen from `pool`. If set, then the IP must be available in the resolved `pool`." - }, - { - "long": "ip-version", - "values": [ - "v4", - "v6" - ], - "help": "IP version to use when allocating from the default pool. Only used when both `ip` and `pool` are not specified. Required if multiple default pools of different IP versions exist. Allocation fails if no pool of the requested version is available." - }, { "long": "json-body", "help": "Path to a file that contains the full json body." @@ -2349,10 +2205,6 @@ { "long": "name" }, - { - "long": "pool", - "help": "The parent IP pool that a floating IP is pulled from. If unset, the default pool is selected." - }, { "long": "profile", "help": "Configuration profile to use for commands", @@ -3153,14 +3005,6 @@ "long": "instance", "help": "Name or ID of the instance" }, - { - "long": "ip-version", - "values": [ - "v4", - "v6" - ], - "help": "IP version to use when allocating from the default pool. Only used when `pool` is not specified. Required if multiple default pools of different IP versions exist. Allocation fails if no pool of the requested version is available." - }, { "long": "json-body", "help": "Path to a file that contains the full json body." @@ -3169,10 +3013,6 @@ "long": "json-body-template", "help": "XXX" }, - { - "long": "pool", - "help": "Name or ID of the IP pool used to allocate an address. If unspecified, the default IP pool will be used." - }, { "long": "profile", "help": "Configuration profile to use for commands", @@ -3319,10 +3159,6 @@ "long": "instance", "help": "Name or ID of the instance" }, - { - "long": "ip", - "help": "The IP address for the interface. One will be auto-assigned if not provided." - }, { "long": "json-body", "help": "Path to a file that contains the full json body." diff --git a/cli/src/cli_builder.rs b/cli/src/cli_builder.rs index 7b28a92e..47c36119 100644 --- a/cli/src/cli_builder.rs +++ b/cli/src/cli_builder.rs @@ -744,16 +744,8 @@ fn xxx<'a>(command: CliCommand) -> Option<&'a str> { CliCommand::ProbeView => Some("experimental system probe view"), CliCommand::MulticastGroupList => Some("experimental multicast-group list"), - CliCommand::MulticastGroupCreate => Some("experimental multicast-group create"), CliCommand::MulticastGroupView => Some("experimental multicast-group view"), - CliCommand::MulticastGroupDelete => Some("experimental multicast-group delete"), - CliCommand::MulticastGroupUpdate => Some("experimental multicast-group update"), CliCommand::MulticastGroupMemberList => Some("experimental multicast-group member list"), - CliCommand::MulticastGroupMemberAdd => Some("experimental multicast-group member add"), - CliCommand::MulticastGroupMemberRemove => { - Some("experimental multicast-group member remove") - } - CliCommand::LookupMulticastGroupByIp => Some("experimental multicast-group lookup-by-ip"), // Metrics-related subcommands CliCommand::TimeseriesQuery => Some("experimental timeseries query"), diff --git a/cli/src/cmd_instance.rs b/cli/src/cmd_instance.rs index 1cef5b3c..27812ec5 100644 --- a/cli/src/cmd_instance.rs +++ b/cli/src/cmd_instance.rs @@ -9,7 +9,7 @@ use async_trait::async_trait; use clap::Parser; use oxide::types::{ ByteCount, DiskBackend, DiskSource, ExternalIpCreate, InstanceCpuCount, InstanceDiskAttachment, - IpVersion, Name, NameOrId, + IpVersion, Name, NameOrId, PoolSelector, }; use oxide::ClientInstancesExt; @@ -278,8 +278,9 @@ impl crate::AuthenticatedCmd for CmdInstanceFromImage { size: self.size.clone(), }) .external_ips(vec![ExternalIpCreate::Ephemeral { - ip_version: Some(IpVersion::V4), - pool: None, + pool_selector: PoolSelector::Auto { + ip_version: Some(IpVersion::V4), + }, }]) .hostname(self.hostname.clone()) .memory(self.memory.clone()) diff --git a/cli/src/generated_cli.rs b/cli/src/generated_cli.rs index 567c7456..67d4e576 100644 --- a/cli/src/generated_cli.rs +++ b/cli/src/generated_cli.rs @@ -158,13 +158,8 @@ impl Cli { CliCommand::CurrentUserSshKeyDelete => Self::cli_current_user_ssh_key_delete(), CliCommand::SiloMetric => Self::cli_silo_metric(), CliCommand::MulticastGroupList => Self::cli_multicast_group_list(), - CliCommand::MulticastGroupCreate => Self::cli_multicast_group_create(), CliCommand::MulticastGroupView => Self::cli_multicast_group_view(), - CliCommand::MulticastGroupUpdate => Self::cli_multicast_group_update(), - CliCommand::MulticastGroupDelete => Self::cli_multicast_group_delete(), CliCommand::MulticastGroupMemberList => Self::cli_multicast_group_member_list(), - CliCommand::MulticastGroupMemberAdd => Self::cli_multicast_group_member_add(), - CliCommand::MulticastGroupMemberRemove => Self::cli_multicast_group_member_remove(), CliCommand::InstanceNetworkInterfaceList => Self::cli_instance_network_interface_list(), CliCommand::InstanceNetworkInterfaceCreate => { Self::cli_instance_network_interface_create() @@ -245,7 +240,6 @@ impl Cli { CliCommand::IpPoolServiceRangeAdd => Self::cli_ip_pool_service_range_add(), CliCommand::IpPoolServiceRangeRemove => Self::cli_ip_pool_service_range_remove(), CliCommand::SystemMetric => Self::cli_system_metric(), - CliCommand::LookupMulticastGroupByIp => Self::cli_lookup_multicast_group_by_ip(), CliCommand::NetworkingAddressLotList => Self::cli_networking_address_lot_list(), CliCommand::NetworkingAddressLotCreate => Self::cli_networking_address_lot_create(), CliCommand::NetworkingAddressLotView => Self::cli_networking_address_lot_view(), @@ -540,12 +534,6 @@ impl Cli { .value_parser(::clap::value_parser!(::std::string::String)) .required_unless_present("json-body"), ) - .arg( - ::clap::Arg::new("ip-pool") - .long("ip-pool") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(false), - ) .arg( ::clap::Arg::new("name") .long("name") @@ -2038,51 +2026,12 @@ impl Cli { .value_parser(::clap::value_parser!(::std::string::String)) .required_unless_present("json-body"), ) - .arg( - ::clap::Arg::new("ip") - .long("ip") - .value_parser(::clap::value_parser!(::std::net::IpAddr)) - .required(false) - .help( - "An IP address to reserve for use as a floating IP. This field is \ - optional: when not set, an address will be automatically chosen from \ - `pool`. If set, then the IP must be available in the resolved `pool`.", - ), - ) - .arg( - ::clap::Arg::new("ip-version") - .long("ip-version") - .value_parser(::clap::builder::TypedValueParser::map( - ::clap::builder::PossibleValuesParser::new([ - types::IpVersion::V4.to_string(), - types::IpVersion::V6.to_string(), - ]), - |s| types::IpVersion::try_from(s).unwrap(), - )) - .required(false) - .help( - "IP version to use when allocating from the default pool. Only used when \ - both `ip` and `pool` are not specified. Required if multiple default \ - pools of different IP versions exist. Allocation fails if no pool of the \ - requested version is available.", - ), - ) .arg( ::clap::Arg::new("name") .long("name") .value_parser(::clap::value_parser!(types::Name)) .required_unless_present("json-body"), ) - .arg( - ::clap::Arg::new("pool") - .long("pool") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(false) - .help( - "The parent IP pool that a floating IP is pulled from. If unset, the \ - default pool is selected.", - ), - ) .arg( ::clap::Arg::new("project") .long("project") @@ -2992,34 +2941,6 @@ impl Cli { .required(true) .help("Name or ID of the instance"), ) - .arg( - ::clap::Arg::new("ip-version") - .long("ip-version") - .value_parser(::clap::builder::TypedValueParser::map( - ::clap::builder::PossibleValuesParser::new([ - types::IpVersion::V4.to_string(), - types::IpVersion::V6.to_string(), - ]), - |s| types::IpVersion::try_from(s).unwrap(), - )) - .required(false) - .help( - "IP version to use when allocating from the default pool. Only used when \ - `pool` is not specified. Required if multiple default pools of different \ - IP versions exist. Allocation fails if no pool of the requested version \ - is available.", - ), - ) - .arg( - ::clap::Arg::new("pool") - .long("pool") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(false) - .help( - "Name or ID of the IP pool used to allocate an address. If unspecified, \ - the default IP pool will be used.", - ), - ) .arg( ::clap::Arg::new("project") .long("project") @@ -3072,6 +2993,13 @@ impl Cli { .required(true) .help("Name or ID of the instance"), ) + .arg( + ::clap::Arg::new("limit") + .long("limit") + .value_parser(::clap::value_parser!(::std::num::NonZeroU32)) + .required(false) + .help("Maximum number of items returned by a single call"), + ) .arg( ::clap::Arg::new("project") .long("project") @@ -3079,7 +3007,18 @@ impl Cli { .required(false) .help("Name or ID of the project"), ) - .about("List multicast groups for instance") + .arg( + ::clap::Arg::new("sort-by") + .long("sort-by") + .value_parser(::clap::builder::TypedValueParser::map( + ::clap::builder::PossibleValuesParser::new([ + types::IdSortMode::IdAscending.to_string(), + ]), + |s| types::IdSortMode::try_from(s).unwrap(), + )) + .required(false), + ) + .about("List multicast groups for an instance.") } pub fn cli_instance_multicast_group_join() -> ::clap::Command { @@ -3091,12 +3030,28 @@ impl Cli { .required(true) .help("Name or ID of the instance"), ) + .arg( + ::clap::Arg::new("ip-version") + .long("ip-version") + .value_parser(::clap::builder::TypedValueParser::map( + ::clap::builder::PossibleValuesParser::new([ + types::IpVersion::V4.to_string(), + types::IpVersion::V6.to_string(), + ]), + |s| types::IpVersion::try_from(s).unwrap(), + )) + .required(false) + .help( + "IP version for pool selection when creating a group by name. Required if \ + both IPv4 and IPv6 default multicast pools are linked.", + ), + ) .arg( ::clap::Arg::new("multicast-group") .long("multicast-group") - .value_parser(::clap::value_parser!(types::NameOrId)) + .value_parser(::clap::value_parser!(types::MulticastGroupIdentifier)) .required(true) - .help("Name or ID of the multicast group"), + .help("Name, ID, or IP address of the multicast group"), ) .arg( ::clap::Arg::new("project") @@ -3105,11 +3060,40 @@ impl Cli { .required(false) .help("Name or ID of the project"), ) - .about("Join multicast group.") + .arg( + ::clap::Arg::new("json-body") + .long("json-body") + .value_name("JSON-FILE") + .required(false) + .value_parser(::clap::value_parser!(std::path::PathBuf)) + .help("Path to a file that contains the full json body."), + ) + .arg( + ::clap::Arg::new("json-body-template") + .long("json-body-template") + .action(::clap::ArgAction::SetTrue) + .help("XXX"), + ) + .about("Join a multicast group.") .long_about( "This is functionally equivalent to adding the instance via the group's member \ management endpoint or updating the instance's `multicast_groups` field. All \ - approaches modify the same membership and trigger reconciliation.", + approaches modify the same membership and trigger \ + reconciliation.\n\nAuthorization: requires Modify on the instance identified in \ + the URL path (checked first) and Read on the multicast group. Checking instance \ + permission first prevents creating orphaned groups when the instance check \ + fails.\n\nGroup Identification: Groups can be referenced by name, IP address, or \ + UUID. All three are fleet-wide unique identifiers: - By name: If group doesn't \ + exist, it's implicitly created with an auto-allocated IP from a multicast pool \ + linked to the caller's silo. Pool selection prefers the default pool; if none, \ + selects alphabetically. - By IP: If group doesn't exist, it's implicitly created \ + using that IP. The pool is determined by which pool contains the IP. - By UUID: \ + Group must already exist.\n\nSource IP filtering: - Duplicate IPs in the request \ + are automatically deduplicated. - Maximum of 64 source IPs allowed (per RFC \ + 3376, IGMPv3). - ASM: Sources are optional. Providing sources enables source \ + filtering via IGMPv3/MLDv2 even for ASM addresses. - SSM: Sources are required. \ + SSM addresses (232.0.0.0/8 for IPv4, ff3x::/32 for IPv6) must have at least one \ + source specified.", ) } @@ -3125,9 +3109,9 @@ impl Cli { .arg( ::clap::Arg::new("multicast-group") .long("multicast-group") - .value_parser(::clap::value_parser!(types::NameOrId)) + .value_parser(::clap::value_parser!(types::MulticastGroupIdentifier)) .required(true) - .help("Name or ID of the multicast group"), + .help("Name, ID, or IP address of the multicast group"), ) .arg( ::clap::Arg::new("project") @@ -3136,11 +3120,14 @@ impl Cli { .required(false) .help("Name or ID of the project"), ) - .about("Leave multicast group.") + .about("Leave a multicast group.") .long_about( - "This is functionally equivalent to removing the instance via the group's member \ - management endpoint or updating the instance's `multicast_groups` field. All \ - approaches modify the same membership and trigger reconciliation.", + "The group can be specified by name, UUID, or multicast IP address. All three are \ + fleet-wide unique identifiers.\n\nThis is functionally equivalent to removing \ + the instance via the group's member management endpoint or updating the \ + instance's `multicast_groups` field. All approaches modify the same membership \ + and trigger reconciliation.\n\nAuthorization: requires Modify on the instance \ + (checked first) and Read on the multicast group.", ) } @@ -4121,75 +4108,7 @@ impl Cli { )) .required(false), ) - .about("List all multicast groups.") - } - - pub fn cli_multicast_group_create() -> ::clap::Command { - ::clap::Command::new("") - .arg( - ::clap::Arg::new("description") - .long("description") - .value_parser(::clap::value_parser!(::std::string::String)) - .required_unless_present("json-body"), - ) - .arg( - ::clap::Arg::new("multicast-ip") - .long("multicast-ip") - .value_parser(::clap::value_parser!(::std::net::IpAddr)) - .required(false) - .help( - "The multicast IP address to allocate. If None, one will be allocated \ - from the default pool.", - ), - ) - .arg( - ::clap::Arg::new("mvlan") - .long("mvlan") - .value_parser(::clap::value_parser!(u16)) - .required(false) - .help( - "Multicast VLAN (MVLAN) for egress multicast traffic to upstream \ - networks. Tags packets leaving the rack to traverse VLAN-segmented \ - upstream networks.\n\nValid range: 2-4094 (VLAN IDs 0-1 are reserved by \ - IEEE 802.1Q standard).", - ), - ) - .arg( - ::clap::Arg::new("name") - .long("name") - .value_parser(::clap::value_parser!(types::Name)) - .required_unless_present("json-body"), - ) - .arg( - ::clap::Arg::new("pool") - .long("pool") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(false) - .help( - "Name or ID of the IP pool to allocate from. If None, uses the default \ - multicast pool.", - ), - ) - .arg( - ::clap::Arg::new("json-body") - .long("json-body") - .value_name("JSON-FILE") - .required(false) - .value_parser(::clap::value_parser!(std::path::PathBuf)) - .help("Path to a file that contains the full json body."), - ) - .arg( - ::clap::Arg::new("json-body-template") - .long("json-body-template") - .action(::clap::ArgAction::SetTrue) - .help("XXX"), - ) - .about("Create a multicast group.") - .long_about( - "Multicast groups are fleet-scoped resources that can be joined by instances \ - across projects and silos. A single multicast IP serves all group members \ - regardless of project or silo boundaries.", - ) + .about("List multicast groups.") } pub fn cli_multicast_group_view() -> ::clap::Command { @@ -4197,72 +4116,15 @@ impl Cli { .arg( ::clap::Arg::new("multicast-group") .long("multicast-group") - .value_parser(::clap::value_parser!(types::NameOrId)) + .value_parser(::clap::value_parser!(types::MulticastGroupIdentifier)) .required(true) - .help("Name or ID of the multicast group"), + .help("Name, ID, or IP address of the multicast group"), ) .about("Fetch a multicast group.") - } - - pub fn cli_multicast_group_update() -> ::clap::Command { - ::clap::Command::new("") - .arg( - ::clap::Arg::new("description") - .long("description") - .value_parser(::clap::value_parser!(::std::string::String)) - .required(false), - ) - .arg( - ::clap::Arg::new("multicast-group") - .long("multicast-group") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(true) - .help("Name or ID of the multicast group"), - ) - .arg( - ::clap::Arg::new("mvlan") - .long("mvlan") - .value_parser(::clap::value_parser!(u16)) - .required(false) - .help( - "Multicast VLAN (MVLAN) for egress multicast traffic to upstream \ - networks. Set to null to clear the MVLAN. Valid range: 2-4094 when \ - provided. Omit the field to leave mvlan unchanged.", - ), - ) - .arg( - ::clap::Arg::new("name") - .long("name") - .value_parser(::clap::value_parser!(types::Name)) - .required(false), - ) - .arg( - ::clap::Arg::new("json-body") - .long("json-body") - .value_name("JSON-FILE") - .required(false) - .value_parser(::clap::value_parser!(std::path::PathBuf)) - .help("Path to a file that contains the full json body."), - ) - .arg( - ::clap::Arg::new("json-body-template") - .long("json-body-template") - .action(::clap::ArgAction::SetTrue) - .help("XXX"), - ) - .about("Update a multicast group.") - } - - pub fn cli_multicast_group_delete() -> ::clap::Command { - ::clap::Command::new("") - .arg( - ::clap::Arg::new("multicast-group") - .long("multicast-group") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(true) - .help("Name or ID of the multicast group"), + .long_about( + "The group can be specified by name, UUID, or multicast IP address. (e.g., \ + \"224.1.2.3\" or \"ff38::1\").", ) - .about("Delete a multicast group.") } pub fn cli_multicast_group_member_list() -> ::clap::Command { @@ -4277,9 +4139,9 @@ impl Cli { .arg( ::clap::Arg::new("multicast-group") .long("multicast-group") - .value_parser(::clap::value_parser!(types::NameOrId)) + .value_parser(::clap::value_parser!(types::MulticastGroupIdentifier)) .required(true) - .help("Name or ID of the multicast group"), + .help("Name, ID, or IP address of the multicast group"), ) .arg( ::clap::Arg::new("sort-by") @@ -4293,84 +4155,7 @@ impl Cli { .required(false), ) .about("List members of a multicast group.") - } - - pub fn cli_multicast_group_member_add() -> ::clap::Command { - ::clap::Command::new("") - .arg( - ::clap::Arg::new("instance") - .long("instance") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required_unless_present("json-body") - .help("Name or ID of the instance to add to the multicast group"), - ) - .arg( - ::clap::Arg::new("multicast-group") - .long("multicast-group") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(true) - .help("Name or ID of the multicast group"), - ) - .arg( - ::clap::Arg::new("project") - .long("project") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(false) - .help("Name or ID of the project"), - ) - .arg( - ::clap::Arg::new("json-body") - .long("json-body") - .value_name("JSON-FILE") - .required(false) - .value_parser(::clap::value_parser!(std::path::PathBuf)) - .help("Path to a file that contains the full json body."), - ) - .arg( - ::clap::Arg::new("json-body-template") - .long("json-body-template") - .action(::clap::ArgAction::SetTrue) - .help("XXX"), - ) - .about("Add instance to a multicast group.") - .long_about( - "Functionally equivalent to updating the instance's `multicast_groups` field. \ - Both approaches modify the same underlying membership and trigger the same \ - reconciliation logic.\n\nSpecify instance by name (requires `?project=`) \ - or UUID.", - ) - } - - pub fn cli_multicast_group_member_remove() -> ::clap::Command { - ::clap::Command::new("") - .arg( - ::clap::Arg::new("instance") - .long("instance") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(true) - .help("Name or ID of the instance"), - ) - .arg( - ::clap::Arg::new("multicast-group") - .long("multicast-group") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(true) - .help("Name or ID of the multicast group"), - ) - .arg( - ::clap::Arg::new("project") - .long("project") - .value_parser(::clap::value_parser!(types::NameOrId)) - .required(false) - .help("Name or ID of the project"), - ) - .about("Remove instance from a multicast group.") - .long_about( - "Functionally equivalent to removing the group from the instance's \ - `multicast_groups` field. Both approaches modify the same underlying membership \ - and trigger reconciliation.\n\nSpecify instance by name (requires \ - `?project=`) or UUID.", - ) + .long_about("The group can be specified by name, UUID, or multicast IP address.") } pub fn cli_instance_network_interface_list() -> ::clap::Command { @@ -4430,16 +4215,6 @@ impl Cli { .required(true) .help("Name or ID of the instance"), ) - .arg( - ::clap::Arg::new("ip") - .long("ip") - .value_parser(::clap::value_parser!(::std::net::IpAddr)) - .required(false) - .help( - "The IP address for the interface. One will be auto-assigned if not \ - provided.", - ), - ) .arg( ::clap::Arg::new("name") .long("name") @@ -6291,18 +6066,6 @@ impl Cli { ) } - pub fn cli_lookup_multicast_group_by_ip() -> ::clap::Command { - ::clap::Command::new("") - .arg( - ::clap::Arg::new("address") - .long("address") - .value_parser(::clap::value_parser!(::std::net::IpAddr)) - .required(true) - .help("IP address of the multicast group"), - ) - .about("Look up multicast group by IP address.") - } - pub fn cli_networking_address_lot_list() -> ::clap::Command { ::clap::Command::new("") .arg( @@ -9243,19 +9006,10 @@ impl Cli { } CliCommand::SiloMetric => self.execute_silo_metric(matches).await, CliCommand::MulticastGroupList => self.execute_multicast_group_list(matches).await, - CliCommand::MulticastGroupCreate => self.execute_multicast_group_create(matches).await, CliCommand::MulticastGroupView => self.execute_multicast_group_view(matches).await, - CliCommand::MulticastGroupUpdate => self.execute_multicast_group_update(matches).await, - CliCommand::MulticastGroupDelete => self.execute_multicast_group_delete(matches).await, CliCommand::MulticastGroupMemberList => { self.execute_multicast_group_member_list(matches).await } - CliCommand::MulticastGroupMemberAdd => { - self.execute_multicast_group_member_add(matches).await - } - CliCommand::MulticastGroupMemberRemove => { - self.execute_multicast_group_member_remove(matches).await - } CliCommand::InstanceNetworkInterfaceList => { self.execute_instance_network_interface_list(matches).await } @@ -9372,9 +9126,6 @@ impl Cli { self.execute_ip_pool_service_range_remove(matches).await } CliCommand::SystemMetric => self.execute_system_metric(matches).await, - CliCommand::LookupMulticastGroupByIp => { - self.execute_lookup_multicast_group_by_ip(matches).await - } CliCommand::NetworkingAddressLotList => { self.execute_networking_address_lot_list(matches).await } @@ -9715,10 +9466,6 @@ impl Cli { request = request.body_map(|body| body.description(value.clone())) } - if let Some(value) = matches.get_one::("ip-pool") { - request = request.body_map(|body| body.ip_pool(value.clone())) - } - if let Some(value) = matches.get_one::("name") { request = request.body_map(|body| body.name(value.clone())) } @@ -11608,22 +11355,10 @@ impl Cli { request = request.body_map(|body| body.description(value.clone())) } - if let Some(value) = matches.get_one::<::std::net::IpAddr>("ip") { - request = request.body_map(|body| body.ip(value.clone())) - } - - if let Some(value) = matches.get_one::("ip-version") { - request = request.body_map(|body| body.ip_version(value.clone())) - } - if let Some(value) = matches.get_one::("name") { request = request.body_map(|body| body.name(value.clone())) } - if let Some(value) = matches.get_one::("pool") { - request = request.body_map(|body| body.pool(value.clone())) - } - if let Some(value) = matches.get_one::("project") { request = request.project(value.clone()); } @@ -12534,14 +12269,6 @@ impl Cli { request = request.instance(value.clone()); } - if let Some(value) = matches.get_one::("ip-version") { - request = request.body_map(|body| body.ip_version(value.clone())) - } - - if let Some(value) = matches.get_one::("pool") { - request = request.body_map(|body| body.pool(value.clone())) - } - if let Some(value) = matches.get_one::("project") { request = request.project(value.clone()); } @@ -12606,21 +12333,42 @@ impl Cli { request = request.instance(value.clone()); } + if let Some(value) = matches.get_one::<::std::num::NonZeroU32>("limit") { + request = request.limit(value.clone()); + } + if let Some(value) = matches.get_one::("project") { request = request.project(value.clone()); } - self.config - .execute_instance_multicast_group_list(matches, &mut request)?; - let result = request.send().await; - match result { - Ok(r) => { - self.config.success_item(&r); - Ok(()) - } - Err(r) => { - self.config.error(&r); - Err(anyhow::Error::new(r)) + if let Some(value) = matches.get_one::("sort-by") { + request = request.sort_by(value.clone()); + } + + self.config + .execute_instance_multicast_group_list(matches, &mut request)?; + self.config + .list_start::(); + let mut stream = futures::StreamExt::take( + request.stream(), + matches + .get_one::("limit") + .map_or(usize::MAX, |x| x.get() as usize), + ); + loop { + match futures::TryStreamExt::try_next(&mut stream).await { + Err(r) => { + self.config.list_end_error(&r); + return Err(anyhow::Error::new(r)); + } + Ok(None) => { + self.config + .list_end_success::(); + return Ok(()); + } + Ok(Some(value)) => { + self.config.list_item(&value); + } } } } @@ -12634,7 +12382,11 @@ impl Cli { request = request.instance(value.clone()); } - if let Some(value) = matches.get_one::("multicast-group") { + if let Some(value) = matches.get_one::("ip-version") { + request = request.body_map(|body| body.ip_version(value.clone())) + } + + if let Some(value) = matches.get_one::("multicast-group") { request = request.multicast_group(value.clone()); } @@ -12642,6 +12394,14 @@ impl Cli { request = request.project(value.clone()); } + if let Some(value) = matches.get_one::("json-body") { + let body_txt = std::fs::read_to_string(value) + .with_context(|| format!("failed to read {}", value.display()))?; + let body_value = serde_json::from_str::(&body_txt) + .with_context(|| format!("failed to parse {}", value.display()))?; + request = request.body(body_value); + } + self.config .execute_instance_multicast_group_join(matches, &mut request)?; let result = request.send().await; @@ -12666,7 +12426,7 @@ impl Cli { request = request.instance(value.clone()); } - if let Some(value) = matches.get_one::("multicast-group") { + if let Some(value) = matches.get_one::("multicast-group") { request = request.multicast_group(value.clone()); } @@ -13796,60 +13556,12 @@ impl Cli { } } - pub async fn execute_multicast_group_create( - &self, - matches: &::clap::ArgMatches, - ) -> anyhow::Result<()> { - let mut request = self.client.multicast_group_create(); - if let Some(value) = matches.get_one::<::std::string::String>("description") { - request = request.body_map(|body| body.description(value.clone())) - } - - if let Some(value) = matches.get_one::<::std::net::IpAddr>("multicast-ip") { - request = request.body_map(|body| body.multicast_ip(value.clone())) - } - - if let Some(value) = matches.get_one::("mvlan") { - request = request.body_map(|body| body.mvlan(value.clone())) - } - - if let Some(value) = matches.get_one::("name") { - request = request.body_map(|body| body.name(value.clone())) - } - - if let Some(value) = matches.get_one::("pool") { - request = request.body_map(|body| body.pool(value.clone())) - } - - if let Some(value) = matches.get_one::("json-body") { - let body_txt = std::fs::read_to_string(value) - .with_context(|| format!("failed to read {}", value.display()))?; - let body_value = serde_json::from_str::(&body_txt) - .with_context(|| format!("failed to parse {}", value.display()))?; - request = request.body(body_value); - } - - self.config - .execute_multicast_group_create(matches, &mut request)?; - let result = request.send().await; - match result { - Ok(r) => { - self.config.success_item(&r); - Ok(()) - } - Err(r) => { - self.config.error(&r); - Err(anyhow::Error::new(r)) - } - } - } - pub async fn execute_multicast_group_view( &self, matches: &::clap::ArgMatches, ) -> anyhow::Result<()> { let mut request = self.client.multicast_group_view(); - if let Some(value) = matches.get_one::("multicast-group") { + if let Some(value) = matches.get_one::("multicast-group") { request = request.multicast_group(value.clone()); } @@ -13868,74 +13580,6 @@ impl Cli { } } - pub async fn execute_multicast_group_update( - &self, - matches: &::clap::ArgMatches, - ) -> anyhow::Result<()> { - let mut request = self.client.multicast_group_update(); - if let Some(value) = matches.get_one::<::std::string::String>("description") { - request = request.body_map(|body| body.description(value.clone())) - } - - if let Some(value) = matches.get_one::("multicast-group") { - request = request.multicast_group(value.clone()); - } - - if let Some(value) = matches.get_one::("mvlan") { - request = request.body_map(|body| body.mvlan(value.clone())) - } - - if let Some(value) = matches.get_one::("name") { - request = request.body_map(|body| body.name(value.clone())) - } - - if let Some(value) = matches.get_one::("json-body") { - let body_txt = std::fs::read_to_string(value) - .with_context(|| format!("failed to read {}", value.display()))?; - let body_value = serde_json::from_str::(&body_txt) - .with_context(|| format!("failed to parse {}", value.display()))?; - request = request.body(body_value); - } - - self.config - .execute_multicast_group_update(matches, &mut request)?; - let result = request.send().await; - match result { - Ok(r) => { - self.config.success_item(&r); - Ok(()) - } - Err(r) => { - self.config.error(&r); - Err(anyhow::Error::new(r)) - } - } - } - - pub async fn execute_multicast_group_delete( - &self, - matches: &::clap::ArgMatches, - ) -> anyhow::Result<()> { - let mut request = self.client.multicast_group_delete(); - if let Some(value) = matches.get_one::("multicast-group") { - request = request.multicast_group(value.clone()); - } - - self.config - .execute_multicast_group_delete(matches, &mut request)?; - let result = request.send().await; - match result { - Ok(r) => { - self.config.success_no_item(&r); - Ok(()) - } - Err(r) => { - self.config.error(&r); - Err(anyhow::Error::new(r)) - } - } - } - pub async fn execute_multicast_group_member_list( &self, matches: &::clap::ArgMatches, @@ -13945,7 +13589,7 @@ impl Cli { request = request.limit(value.clone()); } - if let Some(value) = matches.get_one::("multicast-group") { + if let Some(value) = matches.get_one::("multicast-group") { request = request.multicast_group(value.clone()); } @@ -13981,78 +13625,6 @@ impl Cli { } } - pub async fn execute_multicast_group_member_add( - &self, - matches: &::clap::ArgMatches, - ) -> anyhow::Result<()> { - let mut request = self.client.multicast_group_member_add(); - if let Some(value) = matches.get_one::("instance") { - request = request.body_map(|body| body.instance(value.clone())) - } - - if let Some(value) = matches.get_one::("multicast-group") { - request = request.multicast_group(value.clone()); - } - - if let Some(value) = matches.get_one::("project") { - request = request.project(value.clone()); - } - - if let Some(value) = matches.get_one::("json-body") { - let body_txt = std::fs::read_to_string(value) - .with_context(|| format!("failed to read {}", value.display()))?; - let body_value = serde_json::from_str::(&body_txt) - .with_context(|| format!("failed to parse {}", value.display()))?; - request = request.body(body_value); - } - - self.config - .execute_multicast_group_member_add(matches, &mut request)?; - let result = request.send().await; - match result { - Ok(r) => { - self.config.success_item(&r); - Ok(()) - } - Err(r) => { - self.config.error(&r); - Err(anyhow::Error::new(r)) - } - } - } - - pub async fn execute_multicast_group_member_remove( - &self, - matches: &::clap::ArgMatches, - ) -> anyhow::Result<()> { - let mut request = self.client.multicast_group_member_remove(); - if let Some(value) = matches.get_one::("instance") { - request = request.instance(value.clone()); - } - - if let Some(value) = matches.get_one::("multicast-group") { - request = request.multicast_group(value.clone()); - } - - if let Some(value) = matches.get_one::("project") { - request = request.project(value.clone()); - } - - self.config - .execute_multicast_group_member_remove(matches, &mut request)?; - let result = request.send().await; - match result { - Ok(r) => { - self.config.success_no_item(&r); - Ok(()) - } - Err(r) => { - self.config.error(&r); - Err(anyhow::Error::new(r)) - } - } - } - pub async fn execute_instance_network_interface_list( &self, matches: &::clap::ArgMatches, @@ -14115,10 +13687,6 @@ impl Cli { request = request.instance(value.clone()); } - if let Some(value) = matches.get_one::<::std::net::IpAddr>("ip") { - request = request.body_map(|body| body.ip(value.clone())) - } - if let Some(value) = matches.get_one::("name") { request = request.body_map(|body| body.name(value.clone())) } @@ -16278,30 +15846,6 @@ impl Cli { } } - pub async fn execute_lookup_multicast_group_by_ip( - &self, - matches: &::clap::ArgMatches, - ) -> anyhow::Result<()> { - let mut request = self.client.lookup_multicast_group_by_ip(); - if let Some(value) = matches.get_one::<::std::net::IpAddr>("address") { - request = request.address(value.clone()); - } - - self.config - .execute_lookup_multicast_group_by_ip(matches, &mut request)?; - let result = request.send().await; - match result { - Ok(r) => { - self.config.success_item(&r); - Ok(()) - } - Err(r) => { - self.config.error(&r); - Err(anyhow::Error::new(r)) - } - } - } - pub async fn execute_networking_address_lot_list( &self, matches: &::clap::ArgMatches, @@ -20563,14 +20107,6 @@ pub trait CliConfig { Ok(()) } - fn execute_multicast_group_create( - &self, - matches: &::clap::ArgMatches, - request: &mut builder::MulticastGroupCreate, - ) -> anyhow::Result<()> { - Ok(()) - } - fn execute_multicast_group_view( &self, matches: &::clap::ArgMatches, @@ -20579,22 +20115,6 @@ pub trait CliConfig { Ok(()) } - fn execute_multicast_group_update( - &self, - matches: &::clap::ArgMatches, - request: &mut builder::MulticastGroupUpdate, - ) -> anyhow::Result<()> { - Ok(()) - } - - fn execute_multicast_group_delete( - &self, - matches: &::clap::ArgMatches, - request: &mut builder::MulticastGroupDelete, - ) -> anyhow::Result<()> { - Ok(()) - } - fn execute_multicast_group_member_list( &self, matches: &::clap::ArgMatches, @@ -20603,22 +20123,6 @@ pub trait CliConfig { Ok(()) } - fn execute_multicast_group_member_add( - &self, - matches: &::clap::ArgMatches, - request: &mut builder::MulticastGroupMemberAdd, - ) -> anyhow::Result<()> { - Ok(()) - } - - fn execute_multicast_group_member_remove( - &self, - matches: &::clap::ArgMatches, - request: &mut builder::MulticastGroupMemberRemove, - ) -> anyhow::Result<()> { - Ok(()) - } - fn execute_instance_network_interface_list( &self, matches: &::clap::ArgMatches, @@ -21131,14 +20635,6 @@ pub trait CliConfig { Ok(()) } - fn execute_lookup_multicast_group_by_ip( - &self, - matches: &::clap::ArgMatches, - request: &mut builder::LookupMulticastGroupByIp, - ) -> anyhow::Result<()> { - Ok(()) - } - fn execute_networking_address_lot_list( &self, matches: &::clap::ArgMatches, @@ -22046,13 +21542,8 @@ pub enum CliCommand { CurrentUserSshKeyDelete, SiloMetric, MulticastGroupList, - MulticastGroupCreate, MulticastGroupView, - MulticastGroupUpdate, - MulticastGroupDelete, MulticastGroupMemberList, - MulticastGroupMemberAdd, - MulticastGroupMemberRemove, InstanceNetworkInterfaceList, InstanceNetworkInterfaceCreate, InstanceNetworkInterfaceView, @@ -22117,7 +21608,6 @@ pub enum CliCommand { IpPoolServiceRangeAdd, IpPoolServiceRangeRemove, SystemMetric, - LookupMulticastGroupByIp, NetworkingAddressLotList, NetworkingAddressLotCreate, NetworkingAddressLotView, @@ -22341,13 +21831,8 @@ impl CliCommand { CliCommand::CurrentUserSshKeyDelete, CliCommand::SiloMetric, CliCommand::MulticastGroupList, - CliCommand::MulticastGroupCreate, CliCommand::MulticastGroupView, - CliCommand::MulticastGroupUpdate, - CliCommand::MulticastGroupDelete, CliCommand::MulticastGroupMemberList, - CliCommand::MulticastGroupMemberAdd, - CliCommand::MulticastGroupMemberRemove, CliCommand::InstanceNetworkInterfaceList, CliCommand::InstanceNetworkInterfaceCreate, CliCommand::InstanceNetworkInterfaceView, @@ -22412,7 +21897,6 @@ impl CliCommand { CliCommand::IpPoolServiceRangeAdd, CliCommand::IpPoolServiceRangeRemove, CliCommand::SystemMetric, - CliCommand::LookupMulticastGroupByIp, CliCommand::NetworkingAddressLotList, CliCommand::NetworkingAddressLotCreate, CliCommand::NetworkingAddressLotView, diff --git a/cli/tests/data/test_instance_create.stdin b/cli/tests/data/test_instance_create.stdin index 28a0bf72..f9f52988 100644 --- a/cli/tests/data/test_instance_create.stdin +++ b/cli/tests/data/test_instance_create.stdin @@ -25,7 +25,7 @@ "name": "name", "ncpus": 4, "network_interfaces": { - "type": "default" + "type": "default_dual_stack" }, "start": true, "user_data": "" diff --git a/oxide.json b/oxide.json index be74d8a2..141074e7 100644 --- a/oxide.json +++ b/oxide.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "2026010100.0.0" + "version": "2026010800.0.0" }, "paths": { "/device/auth": { @@ -4283,9 +4283,29 @@ "tags": [ "experimental" ], - "summary": "List multicast groups for instance", + "summary": "List multicast groups for an instance.", "operationId": "instance_multicast_group_list", "parameters": [ + { + "in": "query", + "name": "limit", + "description": "Maximum number of items returned by a single call", + "schema": { + "nullable": true, + "type": "integer", + "format": "uint32", + "minimum": 1 + } + }, + { + "in": "query", + "name": "page_token", + "description": "Token returned by previous call to retrieve the subsequent page", + "schema": { + "nullable": true, + "type": "string" + } + }, { "in": "query", "name": "project", @@ -4294,6 +4314,13 @@ "$ref": "#/components/schemas/NameOrId" } }, + { + "in": "query", + "name": "sort_by", + "schema": { + "$ref": "#/components/schemas/IdSortMode" + } + }, { "in": "path", "name": "instance", @@ -4321,6 +4348,9 @@ "5XX": { "$ref": "#/components/responses/Error" } + }, + "x-dropshot-pagination": { + "required": [] } } }, @@ -4329,8 +4359,8 @@ "tags": [ "experimental" ], - "summary": "Join multicast group.", - "description": "This is functionally equivalent to adding the instance via the group's member management endpoint or updating the instance's `multicast_groups` field. All approaches modify the same membership and trigger reconciliation.", + "summary": "Join a multicast group.", + "description": "This is functionally equivalent to adding the instance via the group's member management endpoint or updating the instance's `multicast_groups` field. All approaches modify the same membership and trigger reconciliation.\n\nAuthorization: requires Modify on the instance identified in the URL path (checked first) and Read on the multicast group. Checking instance permission first prevents creating orphaned groups when the instance check fails.\n\nGroup Identification: Groups can be referenced by name, IP address, or UUID. All three are fleet-wide unique identifiers: - By name: If group doesn't exist, it's implicitly created with an auto-allocated IP from a multicast pool linked to the caller's silo. Pool selection prefers the default pool; if none, selects alphabetically. - By IP: If group doesn't exist, it's implicitly created using that IP. The pool is determined by which pool contains the IP. - By UUID: Group must already exist.\n\nSource IP filtering: - Duplicate IPs in the request are automatically deduplicated. - Maximum of 64 source IPs allowed (per RFC 3376, IGMPv3). - ASM: Sources are optional. Providing sources enables source filtering via IGMPv3/MLDv2 even for ASM addresses. - SSM: Sources are required. SSM addresses (232.0.0.0/8 for IPv4, ff3x::/32 for IPv6) must have at least one source specified.", "operationId": "instance_multicast_group_join", "parameters": [ { @@ -4345,10 +4375,10 @@ { "in": "path", "name": "multicast_group", - "description": "Name or ID of the multicast group", + "description": "Name, ID, or IP address of the multicast group", "required": true, "schema": { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/MulticastGroupIdentifier" } }, { @@ -4360,6 +4390,16 @@ } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstanceMulticastGroupJoin" + } + } + }, + "required": true + }, "responses": { "201": { "description": "successful creation", @@ -4383,8 +4423,8 @@ "tags": [ "experimental" ], - "summary": "Leave multicast group.", - "description": "This is functionally equivalent to removing the instance via the group's member management endpoint or updating the instance's `multicast_groups` field. All approaches modify the same membership and trigger reconciliation.", + "summary": "Leave a multicast group.", + "description": "The group can be specified by name, UUID, or multicast IP address. All three are fleet-wide unique identifiers.\n\nThis is functionally equivalent to removing the instance via the group's member management endpoint or updating the instance's `multicast_groups` field. All approaches modify the same membership and trigger reconciliation.\n\nAuthorization: requires Modify on the instance (checked first) and Read on the multicast group.", "operationId": "instance_multicast_group_leave", "parameters": [ { @@ -4399,10 +4439,10 @@ { "in": "path", "name": "multicast_group", - "description": "Name or ID of the multicast group", + "description": "Name, ID, or IP address of the multicast group", "required": true, "schema": { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/MulticastGroupIdentifier" } }, { @@ -6033,7 +6073,7 @@ "tags": [ "experimental" ], - "summary": "List all multicast groups.", + "summary": "List multicast groups.", "operationId": "multicast_group_list", "parameters": [ { @@ -6085,42 +6125,6 @@ "x-dropshot-pagination": { "required": [] } - }, - "post": { - "tags": [ - "experimental" - ], - "summary": "Create a multicast group.", - "description": "Multicast groups are fleet-scoped resources that can be joined by instances across projects and silos. A single multicast IP serves all group members regardless of project or silo boundaries.", - "operationId": "multicast_group_create", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MulticastGroupCreate" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "successful creation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MulticastGroup" - } - } - } - }, - "4XX": { - "$ref": "#/components/responses/Error" - }, - "5XX": { - "$ref": "#/components/responses/Error" - } - } } }, "/v1/multicast-groups/{multicast_group}": { @@ -6129,64 +6133,19 @@ "experimental" ], "summary": "Fetch a multicast group.", + "description": "The group can be specified by name, UUID, or multicast IP address. (e.g., \"224.1.2.3\" or \"ff38::1\").", "operationId": "multicast_group_view", "parameters": [ { "in": "path", "name": "multicast_group", - "description": "Name or ID of the multicast group", - "required": true, - "schema": { - "$ref": "#/components/schemas/NameOrId" - } - } - ], - "responses": { - "200": { - "description": "successful operation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MulticastGroup" - } - } - } - }, - "4XX": { - "$ref": "#/components/responses/Error" - }, - "5XX": { - "$ref": "#/components/responses/Error" - } - } - }, - "put": { - "tags": [ - "experimental" - ], - "summary": "Update a multicast group.", - "operationId": "multicast_group_update", - "parameters": [ - { - "in": "path", - "name": "multicast_group", - "description": "Name or ID of the multicast group", + "description": "Name, ID, or IP address of the multicast group", "required": true, "schema": { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/MulticastGroupIdentifier" } } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MulticastGroupUpdate" - } - } - }, - "required": true - }, "responses": { "200": { "description": "successful operation", @@ -6205,35 +6164,6 @@ "$ref": "#/components/responses/Error" } } - }, - "delete": { - "tags": [ - "experimental" - ], - "summary": "Delete a multicast group.", - "operationId": "multicast_group_delete", - "parameters": [ - { - "in": "path", - "name": "multicast_group", - "description": "Name or ID of the multicast group", - "required": true, - "schema": { - "$ref": "#/components/schemas/NameOrId" - } - } - ], - "responses": { - "204": { - "description": "successful deletion" - }, - "4XX": { - "$ref": "#/components/responses/Error" - }, - "5XX": { - "$ref": "#/components/responses/Error" - } - } } }, "/v1/multicast-groups/{multicast_group}/members": { @@ -6242,15 +6172,16 @@ "experimental" ], "summary": "List members of a multicast group.", + "description": "The group can be specified by name, UUID, or multicast IP address.", "operationId": "multicast_group_member_list", "parameters": [ { "in": "path", "name": "multicast_group", - "description": "Name or ID of the multicast group", + "description": "Name, ID, or IP address of the multicast group", "required": true, "schema": { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/MulticastGroupIdentifier" } }, { @@ -6302,110 +6233,6 @@ "x-dropshot-pagination": { "required": [] } - }, - "post": { - "tags": [ - "experimental" - ], - "summary": "Add instance to a multicast group.", - "description": "Functionally equivalent to updating the instance's `multicast_groups` field. Both approaches modify the same underlying membership and trigger the same reconciliation logic.\n\nSpecify instance by name (requires `?project=`) or UUID.", - "operationId": "multicast_group_member_add", - "parameters": [ - { - "in": "path", - "name": "multicast_group", - "description": "Name or ID of the multicast group", - "required": true, - "schema": { - "$ref": "#/components/schemas/NameOrId" - } - }, - { - "in": "query", - "name": "project", - "description": "Name or ID of the project", - "schema": { - "$ref": "#/components/schemas/NameOrId" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MulticastGroupMemberAdd" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "successful creation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MulticastGroupMember" - } - } - } - }, - "4XX": { - "$ref": "#/components/responses/Error" - }, - "5XX": { - "$ref": "#/components/responses/Error" - } - } - } - }, - "/v1/multicast-groups/{multicast_group}/members/{instance}": { - "delete": { - "tags": [ - "experimental" - ], - "summary": "Remove instance from a multicast group.", - "description": "Functionally equivalent to removing the group from the instance's `multicast_groups` field. Both approaches modify the same underlying membership and trigger reconciliation.\n\nSpecify instance by name (requires `?project=`) or UUID.", - "operationId": "multicast_group_member_remove", - "parameters": [ - { - "in": "path", - "name": "instance", - "description": "Name or ID of the instance", - "required": true, - "schema": { - "$ref": "#/components/schemas/NameOrId" - } - }, - { - "in": "path", - "name": "multicast_group", - "description": "Name or ID of the multicast group", - "required": true, - "schema": { - "$ref": "#/components/schemas/NameOrId" - } - }, - { - "in": "query", - "name": "project", - "description": "Name or ID of the project", - "schema": { - "$ref": "#/components/schemas/NameOrId" - } - } - ], - "responses": { - "204": { - "description": "successful deletion" - }, - "4XX": { - "$ref": "#/components/responses/Error" - }, - "5XX": { - "$ref": "#/components/responses/Error" - } - } } }, "/v1/network-interfaces": { @@ -9622,62 +9449,23 @@ } } }, - "/v1/system/multicast-groups/by-ip/{address}": { + "/v1/system/networking/address-lot": { "get": { "tags": [ - "experimental" + "system/networking" ], - "summary": "Look up multicast group by IP address.", - "operationId": "lookup_multicast_group_by_ip", + "summary": "List address lots", + "operationId": "networking_address_lot_list", "parameters": [ { - "in": "path", - "name": "address", - "description": "IP address of the multicast group", - "required": true, + "in": "query", + "name": "limit", + "description": "Maximum number of items returned by a single call", "schema": { - "type": "string", - "format": "ip" - } - } - ], - "responses": { - "200": { - "description": "successful operation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MulticastGroup" - } - } - } - }, - "4XX": { - "$ref": "#/components/responses/Error" - }, - "5XX": { - "$ref": "#/components/responses/Error" - } - } - } - }, - "/v1/system/networking/address-lot": { - "get": { - "tags": [ - "system/networking" - ], - "summary": "List address lots", - "operationId": "networking_address_lot_list", - "parameters": [ - { - "in": "query", - "name": "limit", - "description": "Maximum number of items returned by a single call", - "schema": { - "nullable": true, - "type": "integer", - "format": "uint32", - "minimum": 1 + "nullable": true, + "type": "integer", + "format": "uint32", + "minimum": 1 } }, { @@ -14521,6 +14309,68 @@ "lot" ] }, + "AddressSelector": { + "description": "Specify how to allocate a floating IP address.", + "oneOf": [ + { + "description": "Reserve a specific IP address.", + "type": "object", + "properties": { + "ip": { + "description": "The IP address to reserve. Must be available in the pool.", + "type": "string", + "format": "ip" + }, + "pool": { + "nullable": true, + "description": "The pool containing this address. If not specified, the default pool for the address's IP version is used.", + "allOf": [ + { + "$ref": "#/components/schemas/NameOrId" + } + ] + }, + "type": { + "type": "string", + "enum": [ + "explicit" + ] + } + }, + "required": [ + "ip", + "type" + ] + }, + { + "description": "Automatically allocate an IP address from a specified pool.", + "type": "object", + "properties": { + "pool_selector": { + "description": "Pool selection.\n\nIf omitted, this field uses the silo's default pool. If the silo has default pools for both IPv4 and IPv6, the request will fail unless `ip_version` is specified in the pool selector.", + "default": { + "ip_version": null, + "type": "auto" + }, + "allOf": [ + { + "$ref": "#/components/schemas/PoolSelector" + } + ] + }, + "type": { + "type": "string", + "enum": [ + "auto" + ] + } + }, + "required": [ + "type" + ] + } + ] + }, "AffinityGroup": { "description": "View of an Affinity Group", "type": "object", @@ -18947,22 +18797,15 @@ "description": "Parameters for creating an ephemeral IP address for an instance.", "type": "object", "properties": { - "ip_version": { - "nullable": true, - "description": "IP version to use when allocating from the default pool. Only used when `pool` is not specified. Required if multiple default pools of different IP versions exist. Allocation fails if no pool of the requested version is available.", - "default": null, - "allOf": [ - { - "$ref": "#/components/schemas/IpVersion" - } - ] - }, - "pool": { - "nullable": true, - "description": "Name or ID of the IP pool used to allocate an address. If unspecified, the default IP pool will be used.", + "pool_selector": { + "description": "Pool to allocate from.", + "default": { + "ip_version": null, + "type": "auto" + }, "allOf": [ { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/PoolSelector" } ] } @@ -19131,24 +18974,18 @@ "description": "Parameters for creating an external IP address for instances.", "oneOf": [ { - "description": "An IP address providing both inbound and outbound access. The address is automatically assigned from the provided IP pool or the default IP pool if not specified.", + "description": "An IP address providing both inbound and outbound access. The address is automatically assigned from a pool.", "type": "object", "properties": { - "ip_version": { - "nullable": true, - "description": "IP version to use when allocating from the default pool. Only used when `pool` is not specified. Required if multiple default pools of different IP versions exist. Allocation fails if no pool of the requested version is available.", - "default": null, - "allOf": [ - { - "$ref": "#/components/schemas/IpVersion" - } - ] - }, - "pool": { - "nullable": true, + "pool_selector": { + "description": "Pool to allocate from.", + "default": { + "ip_version": null, + "type": "auto" + }, "allOf": [ { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/PoolSelector" } ] }, @@ -19656,36 +19493,26 @@ "description": "Parameters for creating a new floating IP address for instances.", "type": "object", "properties": { - "description": { - "type": "string" - }, - "ip": { - "nullable": true, - "description": "An IP address to reserve for use as a floating IP. This field is optional: when not set, an address will be automatically chosen from `pool`. If set, then the IP must be available in the resolved `pool`.", - "type": "string", - "format": "ip" - }, - "ip_version": { - "nullable": true, - "description": "IP version to use when allocating from the default pool. Only used when both `ip` and `pool` are not specified. Required if multiple default pools of different IP versions exist. Allocation fails if no pool of the requested version is available.", - "default": null, + "address_selector": { + "description": "IP address allocation method.", + "default": { + "pool_selector": { + "ip_version": null, + "type": "auto" + }, + "type": "auto" + }, "allOf": [ { - "$ref": "#/components/schemas/IpVersion" + "$ref": "#/components/schemas/AddressSelector" } ] }, + "description": { + "type": "string" + }, "name": { "$ref": "#/components/schemas/Name" - }, - "pool": { - "nullable": true, - "description": "The parent IP pool that a floating IP is pulled from. If unset, the default pool is selected.", - "allOf": [ - { - "$ref": "#/components/schemas/NameOrId" - } - ] } }, "required": [ @@ -21201,11 +21028,11 @@ ] }, "multicast_groups": { - "description": "The multicast groups this instance should join.\n\nThe instance will be automatically added as a member of the specified multicast groups during creation, enabling it to send and receive multicast traffic for those groups.", + "description": "Multicast groups this instance should join at creation.\n\nGroups can be specified by name, UUID, or IP address. Non-existent groups are created automatically.", "default": [], "type": "array", "items": { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/MulticastGroupJoinSpec" } }, "name": { @@ -21222,7 +21049,7 @@ "network_interfaces": { "description": "The network interfaces to be created for this instance.", "default": { - "type": "default" + "type": "default_dual_stack" }, "allOf": [ { @@ -21328,6 +21155,32 @@ } ] }, + "InstanceMulticastGroupJoin": { + "description": "Parameters for joining an instance to a multicast group.\n\nWhen joining by IP address, the pool containing the multicast IP is auto-discovered from all linked multicast pools.", + "type": "object", + "properties": { + "ip_version": { + "nullable": true, + "description": "IP version for pool selection when creating a group by name. Required if both IPv4 and IPv6 default multicast pools are linked.", + "default": null, + "allOf": [ + { + "$ref": "#/components/schemas/IpVersion" + } + ] + }, + "source_ips": { + "nullable": true, + "description": "Source IPs for source-filtered multicast (SSM). Optional for ASM groups, required for SSM groups (232.0.0.0/8, ff3x::/32).", + "default": null, + "type": "array", + "items": { + "type": "string", + "format": "ip" + } + } + } + }, "InstanceNetworkInterface": { "description": "An `InstanceNetworkInterface` represents a virtual network interface device attached to an instance.", "type": "object", @@ -21346,10 +21199,13 @@ "type": "string", "format": "uuid" }, - "ip": { - "description": "The IP address assigned to this interface.", - "type": "string", - "format": "ip" + "ip_stack": { + "description": "The VPC-private IP stack for this interface.", + "allOf": [ + { + "$ref": "#/components/schemas/PrivateIpStack" + } + ] }, "mac": { "description": "The MAC address assigned to this interface.", @@ -21386,14 +21242,6 @@ "type": "string", "format": "date-time" }, - "transit_ips": { - "description": "A set of additional networks that this interface may send and receive traffic on.", - "default": [], - "type": "array", - "items": { - "$ref": "#/components/schemas/IpNet" - } - }, "vpc_id": { "description": "The VPC to which the interface belongs.", "type": "string", @@ -21404,7 +21252,7 @@ "description", "id", "instance_id", - "ip", + "ip_stack", "mac", "name", "primary", @@ -21440,13 +21288,43 @@ ] }, { - "description": "The default networking configuration for an instance is to create a single primary interface with an automatically-assigned IP address. The IP will be pulled from the Project's default VPC / VPC Subnet.", + "description": "Create a single primary interface with an automatically-assigned IPv4 address.\n\nThe IP will be pulled from the Project's default VPC / VPC Subnet.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "default_ipv4" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Create a single primary interface with an automatically-assigned IPv6 address.\n\nThe IP will be pulled from the Project's default VPC / VPC Subnet.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "default_ipv6" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Create a single primary interface with automatically-assigned IPv4 and IPv6 addresses.\n\nThe IPs will be pulled from the Project's default VPC / VPC Subnet.", "type": "object", "properties": { "type": { "type": "string", "enum": [ - "default" + "default_dual_stack" ] } }, @@ -21478,11 +21356,30 @@ "description": { "type": "string" }, - "ip": { - "nullable": true, - "description": "The IP address for the interface. One will be auto-assigned if not provided.", - "type": "string", - "format": "ip" + "ip_config": { + "description": "The IP stack configuration for this interface.\n\nIf not provided, a default configuration will be used, which creates a dual-stack IPv4 / IPv6 interface.", + "default": { + "type": "dual_stack", + "value": { + "v4": { + "ip": { + "type": "auto" + }, + "transit_ips": [] + }, + "v6": { + "ip": { + "type": "auto" + }, + "transit_ips": [] + } + } + }, + "allOf": [ + { + "$ref": "#/components/schemas/PrivateIpStackCreate" + } + ] }, "name": { "$ref": "#/components/schemas/Name" @@ -21495,14 +21392,6 @@ } ] }, - "transit_ips": { - "description": "A set of additional networks that this interface may send and receive traffic on.", - "default": [], - "type": "array", - "items": { - "$ref": "#/components/schemas/IpNet" - } - }, "vpc_name": { "description": "The VPC in which to create the interface.", "allOf": [ @@ -21562,7 +21451,7 @@ "type": "boolean" }, "transit_ips": { - "description": "A set of additional networks that this interface may send and receive traffic on.", + "description": "A set of additional networks that this interface may send and receive traffic on", "default": [], "type": "array", "items": { @@ -21733,11 +21622,11 @@ }, "multicast_groups": { "nullable": true, - "description": "Multicast groups this instance should join.\n\nWhen specified, this replaces the instance's current multicast group membership with the new set of groups. The instance will leave any groups not listed here and join any new groups that are specified.\n\nIf not provided (None), the instance's multicast group membership will not be changed.", + "description": "Multicast groups this instance should join.\n\nWhen specified, this replaces the instance's current multicast group membership with the new set of groups. The instance will leave any groups not listed here and join any new groups that are specified.\n\nEach entry can specify the group by name, UUID, or IP address, along with optional source IP filtering for SSM (Source-Specific Multicast). When a group doesn't exist, it will be implicitly created using the default multicast pool (or you can specify `ip_version` to disambiguate if needed).\n\nIf not provided, the instance's multicast group membership will not be changed.", "default": null, "type": "array", "items": { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/MulticastGroupJoinSpec" } }, "ncpus": { @@ -22415,37 +22304,117 @@ "v6" ] }, - "Ipv4Net": { - "example": "192.168.1.0/24", - "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and prefix length", - "x-rust-type": { - "crate": "oxnet", - "path": "oxnet::Ipv4Net", - "version": "0.1.0" - }, - "type": "string", - "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" - }, - "Ipv4Range": { - "description": "A non-decreasing IPv4 address range, inclusive of both ends.\n\nThe first address must be less than or equal to the last address.", - "type": "object", - "properties": { - "first": { - "type": "string", - "format": "ipv4" - }, - "last": { - "type": "string", - "format": "ipv4" - } - }, - "required": [ - "first", - "last" - ] - }, - "Ipv6Net": { + "Ipv4Assignment": { + "description": "How a VPC-private IP address is assigned to a network interface.", + "oneOf": [ + { + "description": "Automatically assign an IP address from the VPC Subnet.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "auto" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Explicitly assign a specific address, if available.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "explicit" + ] + }, + "value": { + "type": "string", + "format": "ipv4" + } + }, + "required": [ + "type", + "value" + ] + } + ] + }, + "Ipv4Net": { + "example": "192.168.1.0/24", + "title": "An IPv4 subnet", + "description": "An IPv4 subnet, including prefix and prefix length", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + }, + "type": "string", + "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" + }, + "Ipv4Range": { + "description": "A non-decreasing IPv4 address range, inclusive of both ends.\n\nThe first address must be less than or equal to the last address.", + "type": "object", + "properties": { + "first": { + "type": "string", + "format": "ipv4" + }, + "last": { + "type": "string", + "format": "ipv4" + } + }, + "required": [ + "first", + "last" + ] + }, + "Ipv6Assignment": { + "description": "How a VPC-private IP address is assigned to a network interface.", + "oneOf": [ + { + "description": "Automatically assign an IP address from the VPC Subnet.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "auto" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Explicitly assign a specific address, if available.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "explicit" + ] + }, + "value": { + "type": "string", + "format": "ipv6" + } + }, + "required": [ + "type", + "value" + ] + } + ] + }, + "Ipv6Net": { "example": "fd12:3456::/64", "title": "An IPv6 subnet", "description": "An IPv6 subnet, including prefix and subnet mask", @@ -23079,7 +23048,7 @@ ] }, "source_ips": { - "description": "Source IP addresses for Source-Specific Multicast (SSM). Empty array means any source is allowed.", + "description": "Union of all member source IP addresses (computed, read-only).\n\nThis field shows the combined source IPs across all group members. Individual members may subscribe to different sources; this union reflects all sources that any member is subscribed to. Empty array means no members have source filtering enabled.", "type": "array", "items": { "type": "string", @@ -23113,44 +23082,36 @@ "time_modified" ] }, - "MulticastGroupCreate": { - "description": "Create-time parameters for a multicast group.", + "MulticastGroupIdentifier": { + "title": "A multicast group identifier", + "description": "Can be a UUID, a name, or an IP address", + "type": "string" + }, + "MulticastGroupJoinSpec": { + "description": "Specification for joining a multicast group with optional source filtering.\n\nUsed in `InstanceCreate` and `InstanceUpdate` to specify multicast group membership along with per-member source IP configuration.", "type": "object", "properties": { - "description": { - "type": "string" - }, - "multicast_ip": { - "nullable": true, - "description": "The multicast IP address to allocate. If None, one will be allocated from the default pool.", - "default": null, - "type": "string", - "format": "ip" - }, - "mvlan": { - "nullable": true, - "description": "Multicast VLAN (MVLAN) for egress multicast traffic to upstream networks. Tags packets leaving the rack to traverse VLAN-segmented upstream networks.\n\nValid range: 2-4094 (VLAN IDs 0-1 are reserved by IEEE 802.1Q standard).", - "default": null, - "type": "integer", - "format": "uint16", - "minimum": 0 - }, - "name": { - "$ref": "#/components/schemas/Name" + "group": { + "description": "The multicast group to join, specified by name, UUID, or IP address.", + "allOf": [ + { + "$ref": "#/components/schemas/MulticastGroupIdentifier" + } + ] }, - "pool": { + "ip_version": { "nullable": true, - "description": "Name or ID of the IP pool to allocate from. If None, uses the default multicast pool.", + "description": "IP version for pool selection when creating a group by name. Required if both IPv4 and IPv6 default multicast pools are linked.", "default": null, "allOf": [ { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/IpVersion" } ] }, "source_ips": { "nullable": true, - "description": "Source IP addresses for Source-Specific Multicast (SSM).\n\nNone uses default behavior (Any-Source Multicast). Empty list explicitly allows any source (Any-Source Multicast). Non-empty list restricts to specific sources (SSM).", + "description": "Source IPs for source-filtered multicast (SSM). Optional for ASM groups, required for SSM groups (232.0.0.0/8, ff3x::/32).", "default": null, "type": "array", "items": { @@ -23160,8 +23121,7 @@ } }, "required": [ - "description", - "name" + "group" ] }, "MulticastGroupMember": { @@ -23187,6 +23147,11 @@ "type": "string", "format": "uuid" }, + "multicast_ip": { + "description": "The multicast IP address of the group this member belongs to.", + "type": "string", + "format": "ip" + }, "name": { "description": "unique, mutable, user-controlled identifier for each resource", "allOf": [ @@ -23195,6 +23160,14 @@ } ] }, + "source_ips": { + "description": "Source IP addresses for this member's multicast subscription.\n\n- **ASM**: Sources are optional. Empty array means any source is allowed. Non-empty array enables source filtering (IGMPv3/MLDv2). - **SSM**: Sources are required for SSM addresses (232/8, ff3x::/32).", + "type": "array", + "items": { + "type": "string", + "format": "ip" + } + }, "state": { "description": "Current state of the multicast group membership.", "type": "string" @@ -23215,29 +23188,14 @@ "id", "instance_id", "multicast_group_id", + "multicast_ip", "name", + "source_ips", "state", "time_created", "time_modified" ] }, - "MulticastGroupMemberAdd": { - "description": "Parameters for adding an instance to a multicast group.", - "type": "object", - "properties": { - "instance": { - "description": "Name or ID of the instance to add to the multicast group", - "allOf": [ - { - "$ref": "#/components/schemas/NameOrId" - } - ] - } - }, - "required": [ - "instance" - ] - }, "MulticastGroupMemberResultsPage": { "description": "A single page of results", "type": "object", @@ -23280,39 +23238,6 @@ "items" ] }, - "MulticastGroupUpdate": { - "description": "Update-time parameters for a multicast group.", - "type": "object", - "properties": { - "description": { - "nullable": true, - "type": "string" - }, - "mvlan": { - "nullable": true, - "description": "Multicast VLAN (MVLAN) for egress multicast traffic to upstream networks. Set to null to clear the MVLAN. Valid range: 2-4094 when provided. Omit the field to leave mvlan unchanged.", - "type": "integer", - "format": "uint16", - "minimum": 0 - }, - "name": { - "nullable": true, - "allOf": [ - { - "$ref": "#/components/schemas/Name" - } - ] - }, - "source_ips": { - "nullable": true, - "type": "array", - "items": { - "type": "string", - "format": "ip" - } - } - } - }, "Name": { "title": "A name unique within the parent collection", "description": "Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID, but they may contain a UUID. They can be at most 63 characters long.", @@ -23384,9 +23309,8 @@ "type": "string", "format": "uuid" }, - "ip": { - "type": "string", - "format": "ip" + "ip_config": { + "$ref": "#/components/schemas/PrivateIpConfig" }, "kind": { "$ref": "#/components/schemas/NetworkInterfaceKind" @@ -23405,29 +23329,18 @@ "format": "uint8", "minimum": 0 }, - "subnet": { - "$ref": "#/components/schemas/IpNet" - }, - "transit_ips": { - "default": [], - "type": "array", - "items": { - "$ref": "#/components/schemas/IpNet" - } - }, "vni": { "$ref": "#/components/schemas/Vni" } }, "required": [ "id", - "ip", + "ip_config", "kind", "mac", "name", "primary", "slot", - "subnet", "vni" ] }, @@ -23741,69 +23654,515 @@ "values" ] }, - "Probe": { - "description": "Identity-related metadata that's included in nearly all public API objects", - "type": "object", - "properties": { - "description": { - "description": "human-readable free-form text about a resource", - "type": "string" - }, - "id": { - "description": "unique, immutable, system-controlled identifier for each resource", - "type": "string", - "format": "uuid" - }, - "name": { - "description": "unique, mutable, user-controlled identifier for each resource", - "allOf": [ - { - "$ref": "#/components/schemas/Name" + "PoolSelector": { + "description": "Specify which IP pool to allocate from.", + "oneOf": [ + { + "description": "Use the specified pool by name or ID.", + "type": "object", + "properties": { + "pool": { + "description": "The pool to allocate from.", + "allOf": [ + { + "$ref": "#/components/schemas/NameOrId" + } + ] + }, + "type": { + "type": "string", + "enum": [ + "explicit" + ] } + }, + "required": [ + "pool", + "type" ] }, - "sled": { - "type": "string", - "format": "uuid" - }, - "time_created": { - "description": "timestamp when this resource was created", - "type": "string", - "format": "date-time" - }, - "time_modified": { - "description": "timestamp when this resource was last modified", - "type": "string", - "format": "date-time" - } - }, - "required": [ - "description", - "id", - "name", - "sled", - "time_created", - "time_modified" - ] - }, - "ProbeCreate": { - "description": "Create time parameters for probes.", + { + "description": "Use the default pool for the silo.", + "type": "object", + "properties": { + "ip_version": { + "nullable": true, + "description": "IP version to use when multiple default pools exist. Required if both IPv4 and IPv6 default pools are configured.", + "default": null, + "allOf": [ + { + "$ref": "#/components/schemas/IpVersion" + } + ] + }, + "type": { + "type": "string", + "enum": [ + "auto" + ] + } + }, + "required": [ + "type" + ] + } + ] + }, + "PrivateIpConfig": { + "description": "VPC-private IP address configuration for a network interface.", + "oneOf": [ + { + "description": "The interface has only an IPv4 configuration.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "v4" + ] + }, + "value": { + "$ref": "#/components/schemas/PrivateIpv4Config" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The interface has only an IPv6 configuration.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "v6" + ] + }, + "value": { + "$ref": "#/components/schemas/PrivateIpv6Config" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The interface is dual-stack.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "dual_stack" + ] + }, + "value": { + "type": "object", + "properties": { + "v4": { + "description": "The interface's IPv4 configuration.", + "allOf": [ + { + "$ref": "#/components/schemas/PrivateIpv4Config" + } + ] + }, + "v6": { + "description": "The interface's IPv6 configuration.", + "allOf": [ + { + "$ref": "#/components/schemas/PrivateIpv6Config" + } + ] + } + }, + "required": [ + "v4", + "v6" + ] + } + }, + "required": [ + "type", + "value" + ] + } + ] + }, + "PrivateIpStack": { + "description": "The VPC-private IP stack for a network interface.", + "oneOf": [ + { + "description": "The interface has only an IPv4 stack.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "v4" + ] + }, + "value": { + "$ref": "#/components/schemas/PrivateIpv4Stack" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The interface has only an IPv6 stack.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "v6" + ] + }, + "value": { + "$ref": "#/components/schemas/PrivateIpv6Stack" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The interface is dual-stack IPv4 and IPv6.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "dual_stack" + ] + }, + "value": { + "type": "object", + "properties": { + "v4": { + "$ref": "#/components/schemas/PrivateIpv4Stack" + }, + "v6": { + "$ref": "#/components/schemas/PrivateIpv6Stack" + } + }, + "required": [ + "v4", + "v6" + ] + } + }, + "required": [ + "type", + "value" + ] + } + ] + }, + "PrivateIpStackCreate": { + "description": "Create parameters for a network interface's IP stack.", + "oneOf": [ + { + "description": "The interface has only an IPv4 stack.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "v4" + ] + }, + "value": { + "$ref": "#/components/schemas/PrivateIpv4StackCreate" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The interface has only an IPv6 stack.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "v6" + ] + }, + "value": { + "$ref": "#/components/schemas/PrivateIpv6StackCreate" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The interface has both an IPv4 and IPv6 stack.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "dual_stack" + ] + }, + "value": { + "type": "object", + "properties": { + "v4": { + "$ref": "#/components/schemas/PrivateIpv4StackCreate" + }, + "v6": { + "$ref": "#/components/schemas/PrivateIpv6StackCreate" + } + }, + "required": [ + "v4", + "v6" + ] + } + }, + "required": [ + "type", + "value" + ] + } + ] + }, + "PrivateIpv4Config": { + "description": "VPC-private IPv4 configuration for a network interface.", + "type": "object", + "properties": { + "ip": { + "description": "VPC-private IP address.", + "type": "string", + "format": "ipv4" + }, + "subnet": { + "description": "The IP subnet.", + "allOf": [ + { + "$ref": "#/components/schemas/Ipv4Net" + } + ] + }, + "transit_ips": { + "description": "Additional networks on which the interface can send / receive traffic.", + "default": [], + "type": "array", + "items": { + "$ref": "#/components/schemas/Ipv4Net" + } + } + }, + "required": [ + "ip", + "subnet" + ] + }, + "PrivateIpv4Stack": { + "description": "The VPC-private IPv4 stack for a network interface", + "type": "object", + "properties": { + "ip": { + "description": "The VPC-private IPv4 address for the interface.", + "type": "string", + "format": "ipv4" + }, + "transit_ips": { + "description": "A set of additional IPv4 networks that this interface may send and receive traffic on.", + "type": "array", + "items": { + "$ref": "#/components/schemas/Ipv4Net" + } + } + }, + "required": [ + "ip", + "transit_ips" + ] + }, + "PrivateIpv4StackCreate": { + "description": "Configuration for a network interface's IPv4 addressing.", + "type": "object", + "properties": { + "ip": { + "description": "The VPC-private address to assign to the interface.", + "allOf": [ + { + "$ref": "#/components/schemas/Ipv4Assignment" + } + ] + }, + "transit_ips": { + "description": "Additional IP networks the interface can send / receive on.", + "default": [], + "type": "array", + "items": { + "$ref": "#/components/schemas/Ipv4Net" + } + } + }, + "required": [ + "ip" + ] + }, + "PrivateIpv6Config": { + "description": "VPC-private IPv6 configuration for a network interface.", + "type": "object", + "properties": { + "ip": { + "description": "VPC-private IP address.", + "type": "string", + "format": "ipv6" + }, + "subnet": { + "description": "The IP subnet.", + "allOf": [ + { + "$ref": "#/components/schemas/Ipv6Net" + } + ] + }, + "transit_ips": { + "description": "Additional networks on which the interface can send / receive traffic.", + "type": "array", + "items": { + "$ref": "#/components/schemas/Ipv6Net" + } + } + }, + "required": [ + "ip", + "subnet", + "transit_ips" + ] + }, + "PrivateIpv6Stack": { + "description": "The VPC-private IPv6 stack for a network interface", + "type": "object", + "properties": { + "ip": { + "description": "The VPC-private IPv6 address for the interface.", + "type": "string", + "format": "ipv6" + }, + "transit_ips": { + "description": "A set of additional IPv6 networks that this interface may send and receive traffic on.", + "type": "array", + "items": { + "$ref": "#/components/schemas/Ipv6Net" + } + } + }, + "required": [ + "ip", + "transit_ips" + ] + }, + "PrivateIpv6StackCreate": { + "description": "Configuration for a network interface's IPv6 addressing.", + "type": "object", + "properties": { + "ip": { + "description": "The VPC-private address to assign to the interface.", + "allOf": [ + { + "$ref": "#/components/schemas/Ipv6Assignment" + } + ] + }, + "transit_ips": { + "description": "Additional IP networks the interface can send / receive on.", + "default": [], + "type": "array", + "items": { + "$ref": "#/components/schemas/Ipv6Net" + } + } + }, + "required": [ + "ip" + ] + }, + "Probe": { + "description": "Identity-related metadata that's included in nearly all public API objects", "type": "object", "properties": { "description": { + "description": "human-readable free-form text about a resource", "type": "string" }, - "ip_pool": { - "nullable": true, + "id": { + "description": "unique, immutable, system-controlled identifier for each resource", + "type": "string", + "format": "uuid" + }, + "name": { + "description": "unique, mutable, user-controlled identifier for each resource", "allOf": [ { - "$ref": "#/components/schemas/NameOrId" + "$ref": "#/components/schemas/Name" } ] }, + "sled": { + "type": "string", + "format": "uuid" + }, + "time_created": { + "description": "timestamp when this resource was created", + "type": "string", + "format": "date-time" + }, + "time_modified": { + "description": "timestamp when this resource was last modified", + "type": "string", + "format": "date-time" + } + }, + "required": [ + "description", + "id", + "name", + "sled", + "time_created", + "time_modified" + ] + }, + "ProbeCreate": { + "description": "Create time parameters for probes.", + "type": "object", + "properties": { + "description": { + "type": "string" + }, "name": { "$ref": "#/components/schemas/Name" }, + "pool_selector": { + "description": "Pool to allocate from.", + "default": { + "ip_version": null, + "type": "auto" + }, + "allOf": [ + { + "$ref": "#/components/schemas/PoolSelector" + } + ] + }, "sled": { "type": "string", "format": "uuid" diff --git a/sdk-httpmock/src/generated_httpmock.rs b/sdk-httpmock/src/generated_httpmock.rs index fb94d3b1..061ce497 100644 --- a/sdk-httpmock/src/generated_httpmock.rs +++ b/sdk-httpmock/src/generated_httpmock.rs @@ -6452,6 +6452,28 @@ pub mod operations { Self(self.0.path_matches(re)) } + pub fn limit(self, value: T) -> Self + where + T: Into>, + { + if let Some(value) = value.into() { + Self(self.0.query_param("limit", value.to_string())) + } else { + Self(self.0.query_param_missing("limit")) + } + } + + pub fn page_token<'a, T>(self, value: T) -> Self + where + T: Into>, + { + if let Some(value) = value.into() { + Self(self.0.query_param("page_token", value.to_string())) + } else { + Self(self.0.query_param_missing("page_token")) + } + } + pub fn project<'a, T>(self, value: T) -> Self where T: Into>, @@ -6462,6 +6484,17 @@ pub mod operations { Self(self.0.query_param_missing("project")) } } + + pub fn sort_by(self, value: T) -> Self + where + T: Into>, + { + if let Some(value) = value.into() { + Self(self.0.query_param("sort_by", value.to_string())) + } else { + Self(self.0.query_param_missing("sort_by")) + } + } } pub struct InstanceMulticastGroupListThen(::httpmock::Then); @@ -6525,7 +6558,7 @@ pub mod operations { Self(self.0.path_matches(re)) } - pub fn multicast_group(self, value: &types::NameOrId) -> Self { + pub fn multicast_group(self, value: &types::MulticastGroupIdentifier) -> Self { let re = regex::Regex::new(&format!( "^/v1/instances/.*/multicast-groups/{}$", value.to_string() @@ -6544,6 +6577,10 @@ pub mod operations { Self(self.0.query_param_missing("project")) } } + + pub fn body(self, value: &types::InstanceMulticastGroupJoin) -> Self { + Self(self.0.json_body_obj(value)) + } } pub struct InstanceMulticastGroupJoinThen(::httpmock::Then); @@ -6607,7 +6644,7 @@ pub mod operations { Self(self.0.path_matches(re)) } - pub fn multicast_group(self, value: &types::NameOrId) -> Self { + pub fn multicast_group(self, value: &types::MulticastGroupIdentifier) -> Self { let re = regex::Regex::new(&format!( "^/v1/instances/.*/multicast-groups/{}$", value.to_string() @@ -9153,65 +9190,6 @@ pub mod operations { } } - pub struct MulticastGroupCreateWhen(::httpmock::When); - impl MulticastGroupCreateWhen { - pub fn new(inner: ::httpmock::When) -> Self { - Self( - inner - .method(::httpmock::Method::POST) - .path_matches(regex::Regex::new("^/v1/multicast-groups$").unwrap()), - ) - } - - pub fn into_inner(self) -> ::httpmock::When { - self.0 - } - - pub fn body(self, value: &types::MulticastGroupCreate) -> Self { - Self(self.0.json_body_obj(value)) - } - } - - pub struct MulticastGroupCreateThen(::httpmock::Then); - impl MulticastGroupCreateThen { - pub fn new(inner: ::httpmock::Then) -> Self { - Self(inner) - } - - pub fn into_inner(self) -> ::httpmock::Then { - self.0 - } - - pub fn created(self, value: &types::MulticastGroup) -> Self { - Self( - self.0 - .status(201u16) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn client_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 4u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn server_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 5u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - } - pub struct MulticastGroupViewWhen(::httpmock::When); impl MulticastGroupViewWhen { pub fn new(inner: ::httpmock::When) -> Self { @@ -9226,7 +9204,7 @@ pub mod operations { self.0 } - pub fn multicast_group(self, value: &types::NameOrId) -> Self { + pub fn multicast_group(self, value: &types::MulticastGroupIdentifier) -> Self { let re = regex::Regex::new(&format!("^/v1/multicast-groups/{}$", value.to_string())) .unwrap(); Self(self.0.path_matches(re)) @@ -9273,127 +9251,6 @@ pub mod operations { } } - pub struct MulticastGroupUpdateWhen(::httpmock::When); - impl MulticastGroupUpdateWhen { - pub fn new(inner: ::httpmock::When) -> Self { - Self( - inner - .method(::httpmock::Method::PUT) - .path_matches(regex::Regex::new("^/v1/multicast-groups/[^/]*$").unwrap()), - ) - } - - pub fn into_inner(self) -> ::httpmock::When { - self.0 - } - - pub fn multicast_group(self, value: &types::NameOrId) -> Self { - let re = regex::Regex::new(&format!("^/v1/multicast-groups/{}$", value.to_string())) - .unwrap(); - Self(self.0.path_matches(re)) - } - - pub fn body(self, value: &types::MulticastGroupUpdate) -> Self { - Self(self.0.json_body_obj(value)) - } - } - - pub struct MulticastGroupUpdateThen(::httpmock::Then); - impl MulticastGroupUpdateThen { - pub fn new(inner: ::httpmock::Then) -> Self { - Self(inner) - } - - pub fn into_inner(self) -> ::httpmock::Then { - self.0 - } - - pub fn ok(self, value: &types::MulticastGroup) -> Self { - Self( - self.0 - .status(200u16) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn client_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 4u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn server_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 5u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - } - - pub struct MulticastGroupDeleteWhen(::httpmock::When); - impl MulticastGroupDeleteWhen { - pub fn new(inner: ::httpmock::When) -> Self { - Self( - inner - .method(::httpmock::Method::DELETE) - .path_matches(regex::Regex::new("^/v1/multicast-groups/[^/]*$").unwrap()), - ) - } - - pub fn into_inner(self) -> ::httpmock::When { - self.0 - } - - pub fn multicast_group(self, value: &types::NameOrId) -> Self { - let re = regex::Regex::new(&format!("^/v1/multicast-groups/{}$", value.to_string())) - .unwrap(); - Self(self.0.path_matches(re)) - } - } - - pub struct MulticastGroupDeleteThen(::httpmock::Then); - impl MulticastGroupDeleteThen { - pub fn new(inner: ::httpmock::Then) -> Self { - Self(inner) - } - - pub fn into_inner(self) -> ::httpmock::Then { - self.0 - } - - pub fn no_content(self) -> Self { - Self(self.0.status(204u16)) - } - - pub fn client_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 4u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn server_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 5u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - } - pub struct MulticastGroupMemberListWhen(::httpmock::When); impl MulticastGroupMemberListWhen { pub fn new(inner: ::httpmock::When) -> Self { @@ -9408,7 +9265,7 @@ pub mod operations { self.0 } - pub fn multicast_group(self, value: &types::NameOrId) -> Self { + pub fn multicast_group(self, value: &types::MulticastGroupIdentifier) -> Self { let re = regex::Regex::new(&format!( "^/v1/multicast-groups/{}/members$", value.to_string() @@ -9491,162 +9348,6 @@ pub mod operations { } } - pub struct MulticastGroupMemberAddWhen(::httpmock::When); - impl MulticastGroupMemberAddWhen { - pub fn new(inner: ::httpmock::When) -> Self { - Self( - inner.method(::httpmock::Method::POST).path_matches( - regex::Regex::new("^/v1/multicast-groups/[^/]*/members$").unwrap(), - ), - ) - } - - pub fn into_inner(self) -> ::httpmock::When { - self.0 - } - - pub fn multicast_group(self, value: &types::NameOrId) -> Self { - let re = regex::Regex::new(&format!( - "^/v1/multicast-groups/{}/members$", - value.to_string() - )) - .unwrap(); - Self(self.0.path_matches(re)) - } - - pub fn project<'a, T>(self, value: T) -> Self - where - T: Into>, - { - if let Some(value) = value.into() { - Self(self.0.query_param("project", value.to_string())) - } else { - Self(self.0.query_param_missing("project")) - } - } - - pub fn body(self, value: &types::MulticastGroupMemberAdd) -> Self { - Self(self.0.json_body_obj(value)) - } - } - - pub struct MulticastGroupMemberAddThen(::httpmock::Then); - impl MulticastGroupMemberAddThen { - pub fn new(inner: ::httpmock::Then) -> Self { - Self(inner) - } - - pub fn into_inner(self) -> ::httpmock::Then { - self.0 - } - - pub fn created(self, value: &types::MulticastGroupMember) -> Self { - Self( - self.0 - .status(201u16) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn client_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 4u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn server_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 5u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - } - - pub struct MulticastGroupMemberRemoveWhen(::httpmock::When); - impl MulticastGroupMemberRemoveWhen { - pub fn new(inner: ::httpmock::When) -> Self { - Self(inner.method(::httpmock::Method::DELETE).path_matches( - regex::Regex::new("^/v1/multicast-groups/[^/]*/members/[^/]*$").unwrap(), - )) - } - - pub fn into_inner(self) -> ::httpmock::When { - self.0 - } - - pub fn multicast_group(self, value: &types::NameOrId) -> Self { - let re = regex::Regex::new(&format!( - "^/v1/multicast-groups/{}/members/.*$", - value.to_string() - )) - .unwrap(); - Self(self.0.path_matches(re)) - } - - pub fn instance(self, value: &types::NameOrId) -> Self { - let re = regex::Regex::new(&format!( - "^/v1/multicast-groups/.*/members/{}$", - value.to_string() - )) - .unwrap(); - Self(self.0.path_matches(re)) - } - - pub fn project<'a, T>(self, value: T) -> Self - where - T: Into>, - { - if let Some(value) = value.into() { - Self(self.0.query_param("project", value.to_string())) - } else { - Self(self.0.query_param_missing("project")) - } - } - } - - pub struct MulticastGroupMemberRemoveThen(::httpmock::Then); - impl MulticastGroupMemberRemoveThen { - pub fn new(inner: ::httpmock::Then) -> Self { - Self(inner) - } - - pub fn into_inner(self) -> ::httpmock::Then { - self.0 - } - - pub fn no_content(self) -> Self { - Self(self.0.status(204u16)) - } - - pub fn client_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 4u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn server_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 5u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - } - pub struct InstanceNetworkInterfaceListWhen(::httpmock::When); impl InstanceNetworkInterfaceListWhen { pub fn new(inner: ::httpmock::When) -> Self { @@ -14374,68 +14075,6 @@ pub mod operations { } } - pub struct LookupMulticastGroupByIpWhen(::httpmock::When); - impl LookupMulticastGroupByIpWhen { - pub fn new(inner: ::httpmock::When) -> Self { - Self(inner.method(::httpmock::Method::GET).path_matches( - regex::Regex::new("^/v1/system/multicast-groups/by-ip/[^/]*$").unwrap(), - )) - } - - pub fn into_inner(self) -> ::httpmock::When { - self.0 - } - - pub fn address(self, value: &::std::net::IpAddr) -> Self { - let re = regex::Regex::new(&format!( - "^/v1/system/multicast-groups/by-ip/{}$", - value.to_string() - )) - .unwrap(); - Self(self.0.path_matches(re)) - } - } - - pub struct LookupMulticastGroupByIpThen(::httpmock::Then); - impl LookupMulticastGroupByIpThen { - pub fn new(inner: ::httpmock::Then) -> Self { - Self(inner) - } - - pub fn into_inner(self) -> ::httpmock::Then { - self.0 - } - - pub fn ok(self, value: &types::MulticastGroup) -> Self { - Self( - self.0 - .status(200u16) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn client_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 4u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - - pub fn server_error(self, status: u16, value: &types::Error) -> Self { - assert_eq!(status / 100u16, 5u16); - Self( - self.0 - .status(status) - .header("content-type", "application/json") - .json_body_obj(value), - ) - } - } - pub struct NetworkingAddressLotListWhen(::httpmock::When); impl NetworkingAddressLotListWhen { pub fn new(inner: ::httpmock::When) -> Self { @@ -21892,33 +21531,15 @@ pub trait MockServerExt { fn multicast_group_list(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce(operations::MulticastGroupListWhen, operations::MulticastGroupListThen); - fn multicast_group_create(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce(operations::MulticastGroupCreateWhen, operations::MulticastGroupCreateThen); fn multicast_group_view(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce(operations::MulticastGroupViewWhen, operations::MulticastGroupViewThen); - fn multicast_group_update(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce(operations::MulticastGroupUpdateWhen, operations::MulticastGroupUpdateThen); - fn multicast_group_delete(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce(operations::MulticastGroupDeleteWhen, operations::MulticastGroupDeleteThen); fn multicast_group_member_list(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce( operations::MulticastGroupMemberListWhen, operations::MulticastGroupMemberListThen, ); - fn multicast_group_member_add(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce(operations::MulticastGroupMemberAddWhen, operations::MulticastGroupMemberAddThen); - fn multicast_group_member_remove(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce( - operations::MulticastGroupMemberRemoveWhen, - operations::MulticastGroupMemberRemoveThen, - ); fn instance_network_interface_list(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce( @@ -22159,12 +21780,6 @@ pub trait MockServerExt { fn system_metric(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce(operations::SystemMetricWhen, operations::SystemMetricThen); - fn lookup_multicast_group_by_ip(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce( - operations::LookupMulticastGroupByIpWhen, - operations::LookupMulticastGroupByIpThen, - ); fn networking_address_lot_list(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce( @@ -24082,18 +23697,6 @@ impl MockServerExt for ::httpmock::MockServer { }) } - fn multicast_group_create(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce(operations::MulticastGroupCreateWhen, operations::MulticastGroupCreateThen), - { - self.mock(|when, then| { - config_fn( - operations::MulticastGroupCreateWhen::new(when), - operations::MulticastGroupCreateThen::new(then), - ) - }) - } - fn multicast_group_view(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce(operations::MulticastGroupViewWhen, operations::MulticastGroupViewThen), @@ -24106,30 +23709,6 @@ impl MockServerExt for ::httpmock::MockServer { }) } - fn multicast_group_update(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce(operations::MulticastGroupUpdateWhen, operations::MulticastGroupUpdateThen), - { - self.mock(|when, then| { - config_fn( - operations::MulticastGroupUpdateWhen::new(when), - operations::MulticastGroupUpdateThen::new(then), - ) - }) - } - - fn multicast_group_delete(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce(operations::MulticastGroupDeleteWhen, operations::MulticastGroupDeleteThen), - { - self.mock(|when, then| { - config_fn( - operations::MulticastGroupDeleteWhen::new(when), - operations::MulticastGroupDeleteThen::new(then), - ) - }) - } - fn multicast_group_member_list(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce( @@ -24145,33 +23724,6 @@ impl MockServerExt for ::httpmock::MockServer { }) } - fn multicast_group_member_add(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce(operations::MulticastGroupMemberAddWhen, operations::MulticastGroupMemberAddThen), - { - self.mock(|when, then| { - config_fn( - operations::MulticastGroupMemberAddWhen::new(when), - operations::MulticastGroupMemberAddThen::new(then), - ) - }) - } - - fn multicast_group_member_remove(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce( - operations::MulticastGroupMemberRemoveWhen, - operations::MulticastGroupMemberRemoveThen, - ), - { - self.mock(|when, then| { - config_fn( - operations::MulticastGroupMemberRemoveWhen::new(when), - operations::MulticastGroupMemberRemoveThen::new(then), - ) - }) - } - fn instance_network_interface_list(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce( @@ -24988,21 +24540,6 @@ impl MockServerExt for ::httpmock::MockServer { }) } - fn lookup_multicast_group_by_ip(&self, config_fn: F) -> ::httpmock::Mock<'_> - where - F: FnOnce( - operations::LookupMulticastGroupByIpWhen, - operations::LookupMulticastGroupByIpThen, - ), - { - self.mock(|when, then| { - config_fn( - operations::LookupMulticastGroupByIpWhen::new(when), - operations::LookupMulticastGroupByIpThen::new(then), - ) - }) - } - fn networking_address_lot_list(&self, config_fn: F) -> ::httpmock::Mock<'_> where F: FnOnce( diff --git a/sdk/src/generated_sdk.rs b/sdk/src/generated_sdk.rs index 73501fd8..0ada2b97 100644 --- a/sdk/src/generated_sdk.rs +++ b/sdk/src/generated_sdk.rs @@ -749,6 +749,121 @@ pub mod types { } } + /// Specify how to allocate a floating IP address. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "Specify how to allocate a floating IP address.", + /// "oneOf": [ + /// { + /// "description": "Reserve a specific IP address.", + /// "type": "object", + /// "required": [ + /// "ip", + /// "type" + /// ], + /// "properties": { + /// "ip": { + /// "description": "The IP address to reserve. Must be available in + /// the pool.", + /// "type": "string", + /// "format": "ip" + /// }, + /// "pool": { + /// "description": "The pool containing this address. If not + /// specified, the default pool for the address's IP version is used.", + /// "oneOf": [ + /// { + /// "type": "null" + /// }, + /// { + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/NameOrId" + /// } + /// ] + /// } + /// ] + /// }, + /// "type": { + /// "type": "string", + /// "enum": [ + /// "explicit" + /// ] + /// } + /// } + /// }, + /// { + /// "description": "Automatically allocate an IP address from a + /// specified pool.", + /// "type": "object", + /// "required": [ + /// "type" + /// ], + /// "properties": { + /// "pool_selector": { + /// "description": "Pool selection.\n\nIf omitted, this field uses + /// the silo's default pool. If the silo has default pools for both IPv4 and + /// IPv6, the request will fail unless `ip_version` is specified in the pool + /// selector.", + /// "default": { + /// "ip_version": null, + /// "type": "auto" + /// }, + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/PoolSelector" + /// } + /// ] + /// }, + /// "type": { + /// "type": "string", + /// "enum": [ + /// "auto" + /// ] + /// } + /// } + /// } + /// ] + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + #[serde(tag = "type")] + pub enum AddressSelector { + /// Reserve a specific IP address. + #[serde(rename = "explicit")] + Explicit { + /// The IP address to reserve. Must be available in the pool. + ip: ::std::net::IpAddr, + /// The pool containing this address. If not specified, the default + /// pool for the address's IP version is used. + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pool: ::std::option::Option, + }, + /// Automatically allocate an IP address from a specified pool. + #[serde(rename = "auto")] + Auto { + /// Pool selection. + /// + /// If omitted, this field uses the silo's default pool. If the silo + /// has default pools for both IPv4 and IPv6, the request will fail + /// unless `ip_version` is specified in the pool selector. + #[serde(default = "defaults::address_selector_auto_pool_selector")] + pool_selector: PoolSelector, + }, + } + + impl ::std::convert::From<&Self> for AddressSelector { + fn from(value: &AddressSelector) -> Self { + value.clone() + } + } + /// View of an Affinity Group /// ///
JSON schema @@ -10011,37 +10126,15 @@ pub mod types { /// instance.", /// "type": "object", /// "properties": { - /// "ip_version": { - /// "description": "IP version to use when allocating from the default - /// pool. Only used when `pool` is not specified. Required if multiple - /// default pools of different IP versions exist. Allocation fails if no - /// pool of the requested version is available.", - /// "oneOf": [ - /// { - /// "type": "null" - /// }, + /// "pool_selector": { + /// "description": "Pool to allocate from.", + /// "default": { + /// "ip_version": null, + /// "type": "auto" + /// }, + /// "allOf": [ /// { - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/IpVersion" - /// } - /// ] - /// } - /// ] - /// }, - /// "pool": { - /// "description": "Name or ID of the IP pool used to allocate an - /// address. If unspecified, the default IP pool will be used.", - /// "oneOf": [ - /// { - /// "type": "null" - /// }, - /// { - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/NameOrId" - /// } - /// ] + /// "$ref": "#/components/schemas/PoolSelector" /// } /// ] /// } @@ -10053,16 +10146,9 @@ pub mod types { :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, )] pub struct EphemeralIpCreate { - /// IP version to use when allocating from the default pool. Only used - /// when `pool` is not specified. Required if multiple default pools of - /// different IP versions exist. Allocation fails if no pool of the - /// requested version is available. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub ip_version: ::std::option::Option, - /// Name or ID of the IP pool used to allocate an address. If - /// unspecified, the default IP pool will be used. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub pool: ::std::option::Option, + /// Pool to allocate from. + #[serde(default = "defaults::ephemeral_ip_create_pool_selector")] + pub pool_selector: PoolSelector, } impl ::std::convert::From<&EphemeralIpCreate> for EphemeralIpCreate { @@ -10074,8 +10160,7 @@ pub mod types { impl ::std::default::Default for EphemeralIpCreate { fn default() -> Self { Self { - ip_version: Default::default(), - pool: Default::default(), + pool_selector: defaults::ephemeral_ip_create_pool_selector(), } } } @@ -10362,42 +10447,21 @@ pub mod types { /// "oneOf": [ /// { /// "description": "An IP address providing both inbound and outbound - /// access. The address is automatically assigned from the provided IP pool - /// or the default IP pool if not specified.", + /// access. The address is automatically assigned from a pool.", /// "type": "object", /// "required": [ /// "type" /// ], /// "properties": { - /// "ip_version": { - /// "description": "IP version to use when allocating from the - /// default pool. Only used when `pool` is not specified. Required if - /// multiple default pools of different IP versions exist. Allocation fails - /// if no pool of the requested version is available.", - /// "oneOf": [ - /// { - /// "type": "null" - /// }, - /// { - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/IpVersion" - /// } - /// ] - /// } - /// ] - /// }, - /// "pool": { - /// "oneOf": [ - /// { - /// "type": "null" - /// }, + /// "pool_selector": { + /// "description": "Pool to allocate from.", + /// "default": { + /// "ip_version": null, + /// "type": "auto" + /// }, + /// "allOf": [ /// { - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/NameOrId" - /// } - /// ] + /// "$ref": "#/components/schemas/PoolSelector" /// } /// ] /// }, @@ -10441,18 +10505,12 @@ pub mod types { #[serde(tag = "type")] pub enum ExternalIpCreate { /// An IP address providing both inbound and outbound access. The - /// address is automatically assigned from the provided IP pool or the - /// default IP pool if not specified. + /// address is automatically assigned from a pool. #[serde(rename = "ephemeral")] Ephemeral { - /// IP version to use when allocating from the default pool. Only - /// used when `pool` is not specified. Required if multiple default - /// pools of different IP versions exist. Allocation fails if no - /// pool of the requested version is available. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - ip_version: ::std::option::Option, - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pool: ::std::option::Option, + /// Pool to allocate from. + #[serde(default = "defaults::external_ip_create_ephemeral_pool_selector")] + pool_selector: PoolSelector, }, /// An IP address providing both inbound and outbound access. The /// address is an existing floating IP object assigned to the current @@ -11685,56 +11743,26 @@ pub mod types { /// "name" /// ], /// "properties": { - /// "description": { - /// "type": "string" - /// }, - /// "ip": { - /// "description": "An IP address to reserve for use as a floating IP. - /// This field is optional: when not set, an address will be automatically - /// chosen from `pool`. If set, then the IP must be available in the - /// resolved `pool`.", - /// "type": [ - /// "string", - /// "null" - /// ], - /// "format": "ip" - /// }, - /// "ip_version": { - /// "description": "IP version to use when allocating from the default - /// pool. Only used when both `ip` and `pool` are not specified. Required if - /// multiple default pools of different IP versions exist. Allocation fails - /// if no pool of the requested version is available.", - /// "oneOf": [ - /// { - /// "type": "null" + /// "address_selector": { + /// "description": "IP address allocation method.", + /// "default": { + /// "pool_selector": { + /// "ip_version": null, + /// "type": "auto" /// }, + /// "type": "auto" + /// }, + /// "allOf": [ /// { - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/IpVersion" - /// } - /// ] + /// "$ref": "#/components/schemas/AddressSelector" /// } /// ] /// }, + /// "description": { + /// "type": "string" + /// }, /// "name": { /// "$ref": "#/components/schemas/Name" - /// }, - /// "pool": { - /// "description": "The parent IP pool that a floating IP is pulled - /// from. If unset, the default pool is selected.", - /// "oneOf": [ - /// { - /// "type": "null" - /// }, - /// { - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/NameOrId" - /// } - /// ] - /// } - /// ] /// } /// } /// } @@ -11744,24 +11772,11 @@ pub mod types { :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, )] pub struct FloatingIpCreate { + /// IP address allocation method. + #[serde(default = "defaults::floating_ip_create_address_selector")] + pub address_selector: AddressSelector, pub description: ::std::string::String, - /// An IP address to reserve for use as a floating IP. This field is - /// optional: when not set, an address will be automatically chosen from - /// `pool`. If set, then the IP must be available in the resolved - /// `pool`. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub ip: ::std::option::Option<::std::net::IpAddr>, - /// IP version to use when allocating from the default pool. Only used - /// when both `ip` and `pool` are not specified. Required if multiple - /// default pools of different IP versions exist. Allocation fails if no - /// pool of the requested version is available. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub ip_version: ::std::option::Option, pub name: Name, - /// The parent IP pool that a floating IP is pulled from. If unset, the - /// default pool is selected. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub pool: ::std::option::Option, } impl ::std::convert::From<&FloatingIpCreate> for FloatingIpCreate { @@ -15356,14 +15371,13 @@ pub mod types { /// ] /// }, /// "multicast_groups": { - /// "description": "The multicast groups this instance should - /// join.\n\nThe instance will be automatically added as a member of the - /// specified multicast groups during creation, enabling it to send and - /// receive multicast traffic for those groups.", + /// "description": "Multicast groups this instance should join at + /// creation.\n\nGroups can be specified by name, UUID, or IP address. + /// Non-existent groups are created automatically.", /// "default": [], /// "type": "array", /// "items": { - /// "$ref": "#/components/schemas/NameOrId" + /// "$ref": "#/components/schemas/MulticastGroupJoinSpec" /// } /// }, /// "name": { @@ -15382,7 +15396,7 @@ pub mod types { /// "description": "The network interfaces to be created for this /// instance.", /// "default": { - /// "type": "default" + /// "type": "default_dual_stack" /// }, /// "allOf": [ /// { @@ -15495,13 +15509,12 @@ pub mod types { pub hostname: Hostname, /// The amount of RAM (in bytes) to be allocated to the instance pub memory: ByteCount, - /// The multicast groups this instance should join. + /// Multicast groups this instance should join at creation. /// - /// The instance will be automatically added as a member of the - /// specified multicast groups during creation, enabling it to send and - /// receive multicast traffic for those groups. + /// Groups can be specified by name, UUID, or IP address. Non-existent + /// groups are created automatically. #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] - pub multicast_groups: ::std::vec::Vec, + pub multicast_groups: ::std::vec::Vec, pub name: Name, /// The number of vCPUs to be allocated to the instance pub ncpus: InstanceCpuCount, @@ -15644,6 +15657,89 @@ pub mod types { } } + /// Parameters for joining an instance to a multicast group. + /// + /// When joining by IP address, the pool containing the multicast IP is + /// auto-discovered from all linked multicast pools. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "Parameters for joining an instance to a multicast + /// group.\n\nWhen joining by IP address, the pool containing the multicast + /// IP is auto-discovered from all linked multicast pools.", + /// "type": "object", + /// "properties": { + /// "ip_version": { + /// "description": "IP version for pool selection when creating a group + /// by name. Required if both IPv4 and IPv6 default multicast pools are + /// linked.", + /// "oneOf": [ + /// { + /// "type": "null" + /// }, + /// { + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/IpVersion" + /// } + /// ] + /// } + /// ] + /// }, + /// "source_ips": { + /// "description": "Source IPs for source-filtered multicast (SSM). + /// Optional for ASM groups, required for SSM groups (232.0.0.0/8, + /// ff3x::/32).", + /// "type": [ + /// "array", + /// "null" + /// ], + /// "items": { + /// "type": "string", + /// "format": "ip" + /// } + /// } + /// } + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + pub struct InstanceMulticastGroupJoin { + /// IP version for pool selection when creating a group by name. + /// Required if both IPv4 and IPv6 default multicast pools are linked. + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub ip_version: ::std::option::Option, + /// Source IPs for source-filtered multicast (SSM). Optional for ASM + /// groups, required for SSM groups (232.0.0.0/8, ff3x::/32). + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub source_ips: ::std::option::Option<::std::vec::Vec<::std::net::IpAddr>>, + } + + impl ::std::convert::From<&InstanceMulticastGroupJoin> for InstanceMulticastGroupJoin { + fn from(value: &InstanceMulticastGroupJoin) -> Self { + value.clone() + } + } + + impl ::std::default::Default for InstanceMulticastGroupJoin { + fn default() -> Self { + Self { + ip_version: Default::default(), + source_ips: Default::default(), + } + } + } + + impl InstanceMulticastGroupJoin { + pub fn builder() -> builder::InstanceMulticastGroupJoin { + Default::default() + } + } + /// An `InstanceNetworkInterface` represents a virtual network interface /// device attached to an instance. /// @@ -15658,7 +15754,7 @@ pub mod types { /// "description", /// "id", /// "instance_id", - /// "ip", + /// "ip_stack", /// "mac", /// "name", /// "primary", @@ -15683,10 +15779,13 @@ pub mod types { /// "type": "string", /// "format": "uuid" /// }, - /// "ip": { - /// "description": "The IP address assigned to this interface.", - /// "type": "string", - /// "format": "ip" + /// "ip_stack": { + /// "description": "The VPC-private IP stack for this interface.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/PrivateIpStack" + /// } + /// ] /// }, /// "mac": { /// "description": "The MAC address assigned to this interface.", @@ -15725,15 +15824,6 @@ pub mod types { /// "type": "string", /// "format": "date-time" /// }, - /// "transit_ips": { - /// "description": "A set of additional networks that this interface - /// may send and receive traffic on.", - /// "default": [], - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/IpNet" - /// } - /// }, /// "vpc_id": { /// "description": "The VPC to which the interface belongs.", /// "type": "string", @@ -15753,8 +15843,8 @@ pub mod types { pub id: ::uuid::Uuid, /// The Instance to which the interface belongs. pub instance_id: ::uuid::Uuid, - /// The IP address assigned to this interface. - pub ip: ::std::net::IpAddr, + /// The VPC-private IP stack for this interface. + pub ip_stack: PrivateIpStack, /// The MAC address assigned to this interface. pub mac: MacAddr, /// unique, mutable, user-controlled identifier for each resource @@ -15768,10 +15858,6 @@ pub mod types { pub time_created: ::chrono::DateTime<::chrono::offset::Utc>, /// timestamp when this resource was last modified pub time_modified: ::chrono::DateTime<::chrono::offset::Utc>, - /// A set of additional networks that this interface may send and - /// receive traffic on. - #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] - pub transit_ips: ::std::vec::Vec, /// The VPC to which the interface belongs. pub vpc_id: ::uuid::Uuid, } @@ -15824,9 +15910,8 @@ pub mod types { /// } /// }, /// { - /// "description": "The default networking configuration for an - /// instance is to create a single primary interface with an - /// automatically-assigned IP address. The IP will be pulled from the + /// "description": "Create a single primary interface with an + /// automatically-assigned IPv4 address.\n\nThe IP will be pulled from the /// Project's default VPC / VPC Subnet.", /// "type": "object", /// "required": [ @@ -15836,7 +15921,41 @@ pub mod types { /// "type": { /// "type": "string", /// "enum": [ - /// "default" + /// "default_ipv4" + /// ] + /// } + /// } + /// }, + /// { + /// "description": "Create a single primary interface with an + /// automatically-assigned IPv6 address.\n\nThe IP will be pulled from the + /// Project's default VPC / VPC Subnet.", + /// "type": "object", + /// "required": [ + /// "type" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "default_ipv6" + /// ] + /// } + /// } + /// }, + /// { + /// "description": "Create a single primary interface with + /// automatically-assigned IPv4 and IPv6 addresses.\n\nThe IPs will be + /// pulled from the Project's default VPC / VPC Subnet.", + /// "type": "object", + /// "required": [ + /// "type" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "default_dual_stack" /// ] /// } /// } @@ -15872,8 +15991,12 @@ pub mod types { /// designated the primary interface for the instance. #[serde(rename = "create")] Create(::std::vec::Vec), - #[serde(rename = "default")] - Default, + #[serde(rename = "default_ipv4")] + DefaultIpv4, + #[serde(rename = "default_ipv6")] + DefaultIpv6, + #[serde(rename = "default_dual_stack")] + DefaultDualStack, #[serde(rename = "none")] None, } @@ -15911,14 +16034,32 @@ pub mod types { /// "description": { /// "type": "string" /// }, - /// "ip": { - /// "description": "The IP address for the interface. One will be - /// auto-assigned if not provided.", - /// "type": [ - /// "string", - /// "null" - /// ], - /// "format": "ip" + /// "ip_config": { + /// "description": "The IP stack configuration for this + /// interface.\n\nIf not provided, a default configuration will be used, + /// which creates a dual-stack IPv4 / IPv6 interface.", + /// "default": { + /// "type": "dual_stack", + /// "value": { + /// "v4": { + /// "ip": { + /// "type": "auto" + /// }, + /// "transit_ips": [] + /// }, + /// "v6": { + /// "ip": { + /// "type": "auto" + /// }, + /// "transit_ips": [] + /// } + /// } + /// }, + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/PrivateIpStackCreate" + /// } + /// ] /// }, /// "name": { /// "$ref": "#/components/schemas/Name" @@ -15931,15 +16072,6 @@ pub mod types { /// } /// ] /// }, - /// "transit_ips": { - /// "description": "A set of additional networks that this interface - /// may send and receive traffic on.", - /// "default": [], - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/IpNet" - /// } - /// }, /// "vpc_name": { /// "description": "The VPC in which to create the interface.", /// "allOf": [ @@ -15957,17 +16089,15 @@ pub mod types { )] pub struct InstanceNetworkInterfaceCreate { pub description: ::std::string::String, - /// The IP address for the interface. One will be auto-assigned if not - /// provided. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub ip: ::std::option::Option<::std::net::IpAddr>, + /// The IP stack configuration for this interface. + /// + /// If not provided, a default configuration will be used, which creates + /// a dual-stack IPv4 / IPv6 interface. + #[serde(default = "defaults::instance_network_interface_create_ip_config")] + pub ip_config: PrivateIpStackCreate, pub name: Name, /// The VPC Subnet in which to create the interface. pub subnet_name: Name, - /// A set of additional networks that this interface may send and - /// receive traffic on. - #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] - pub transit_ips: ::std::vec::Vec, /// The VPC in which to create the interface. pub vpc_name: Name, } @@ -16089,7 +16219,7 @@ pub mod types { /// }, /// "transit_ips": { /// "description": "A set of additional networks that this interface - /// may send and receive traffic on.", + /// may send and receive traffic on", /// "default": [], /// "type": "array", /// "items": { @@ -16122,7 +16252,7 @@ pub mod types { #[serde(default)] pub primary: bool, /// A set of additional networks that this interface may send and - /// receive traffic on. + /// receive traffic on #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] pub transit_ips: ::std::vec::Vec, } @@ -16571,15 +16701,19 @@ pub mod types { /// "description": "Multicast groups this instance should join.\n\nWhen /// specified, this replaces the instance's current multicast group /// membership with the new set of groups. The instance will leave any - /// groups not listed here and join any new groups that are specified.\n\nIf - /// not provided (None), the instance's multicast group membership will not - /// be changed.", + /// groups not listed here and join any new groups that are + /// specified.\n\nEach entry can specify the group by name, UUID, or IP + /// address, along with optional source IP filtering for SSM + /// (Source-Specific Multicast). When a group doesn't exist, it will be + /// implicitly created using the default multicast pool (or you can specify + /// `ip_version` to disambiguate if needed).\n\nIf not provided, the + /// instance's multicast group membership will not be changed.", /// "type": [ /// "array", /// "null" /// ], /// "items": { - /// "$ref": "#/components/schemas/NameOrId" + /// "$ref": "#/components/schemas/MulticastGroupJoinSpec" /// } /// }, /// "ncpus": { @@ -16641,10 +16775,16 @@ pub mod types { /// membership with the new set of groups. The instance will leave any /// groups not listed here and join any new groups that are specified. /// - /// If not provided (None), the instance's multicast group membership - /// will not be changed. + /// Each entry can specify the group by name, UUID, or IP address, along + /// with optional source IP filtering for SSM (Source-Specific + /// Multicast). When a group doesn't exist, it will be implicitly + /// created using the default multicast pool (or you can specify + /// `ip_version` to disambiguate if needed). + /// + /// If not provided, the instance's multicast group membership will not + /// be changed. #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub multicast_groups: ::std::option::Option<::std::vec::Vec>, + pub multicast_groups: ::std::option::Option<::std::vec::Vec>, /// The number of vCPUs to be allocated to the instance pub ncpus: InstanceCpuCount, } @@ -18355,6 +18495,80 @@ pub mod types { } } + /// How a VPC-private IP address is assigned to a network interface. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "How a VPC-private IP address is assigned to a network + /// interface.", + /// "oneOf": [ + /// { + /// "description": "Automatically assign an IP address from the VPC + /// Subnet.", + /// "type": "object", + /// "required": [ + /// "type" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "auto" + /// ] + /// } + /// } + /// }, + /// { + /// "description": "Explicitly assign a specific address, if + /// available.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "explicit" + /// ] + /// }, + /// "value": { + /// "type": "string", + /// "format": "ipv4" + /// } + /// } + /// } + /// ] + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + #[serde(tag = "type", content = "value")] + pub enum Ipv4Assignment { + #[serde(rename = "auto")] + Auto, + /// Explicitly assign a specific address, if available. + #[serde(rename = "explicit")] + Explicit(::std::net::Ipv4Addr), + } + + impl ::std::convert::From<&Self> for Ipv4Assignment { + fn from(value: &Ipv4Assignment) -> Self { + value.clone() + } + } + + impl ::std::convert::From<::std::net::Ipv4Addr> for Ipv4Assignment { + fn from(value: ::std::net::Ipv4Addr) -> Self { + Self::Explicit(value) + } + } + /// An IPv4 subnet, including prefix and prefix length /// ///
JSON schema @@ -18521,6 +18735,80 @@ pub mod types { } } + /// How a VPC-private IP address is assigned to a network interface. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "How a VPC-private IP address is assigned to a network + /// interface.", + /// "oneOf": [ + /// { + /// "description": "Automatically assign an IP address from the VPC + /// Subnet.", + /// "type": "object", + /// "required": [ + /// "type" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "auto" + /// ] + /// } + /// } + /// }, + /// { + /// "description": "Explicitly assign a specific address, if + /// available.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "explicit" + /// ] + /// }, + /// "value": { + /// "type": "string", + /// "format": "ipv6" + /// } + /// } + /// } + /// ] + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + #[serde(tag = "type", content = "value")] + pub enum Ipv6Assignment { + #[serde(rename = "auto")] + Auto, + /// Explicitly assign a specific address, if available. + #[serde(rename = "explicit")] + Explicit(::std::net::Ipv6Addr), + } + + impl ::std::convert::From<&Self> for Ipv6Assignment { + fn from(value: &Ipv6Assignment) -> Self { + value.clone() + } + } + + impl ::std::convert::From<::std::net::Ipv6Addr> for Ipv6Assignment { + fn from(value: ::std::net::Ipv6Addr) -> Self { + Self::Explicit(value) + } + } + /// An IPv6 subnet, including prefix and subnet mask /// ///
JSON schema @@ -20341,8 +20629,11 @@ pub mod types { /// ] /// }, /// "source_ips": { - /// "description": "Source IP addresses for Source-Specific Multicast - /// (SSM). Empty array means any source is allowed.", + /// "description": "Union of all member source IP addresses (computed, + /// read-only).\n\nThis field shows the combined source IPs across all group + /// members. Individual members may subscribe to different sources; this + /// union reflects all sources that any member is subscribed to. Empty array + /// means no members have source filtering enabled.", /// "type": "array", /// "items": { /// "type": "string", @@ -20385,8 +20676,12 @@ pub mod types { pub mvlan: ::std::option::Option, /// unique, mutable, user-controlled identifier for each resource pub name: Name, - /// Source IP addresses for Source-Specific Multicast (SSM). Empty array - /// means any source is allowed. + /// Union of all member source IP addresses (computed, read-only). + /// + /// This field shows the combined source IPs across all group members. + /// Individual members may subscribe to different sources; this union + /// reflects all sources that any member is subscribed to. Empty array + /// means no members have source filtering enabled. pub source_ips: ::std::vec::Vec<::std::net::IpAddr>, /// Current state of the multicast group. pub state: ::std::string::String, @@ -20408,49 +20703,102 @@ pub mod types { } } - /// Create-time parameters for a multicast group. + /// Can be a UUID, a name, or an IP address /// ///
JSON schema /// /// ```json /// { - /// "description": "Create-time parameters for a multicast group.", + /// "title": "A multicast group identifier", + /// "description": "Can be a UUID, a name, or an IP address", + /// "type": "string" + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + schemars :: JsonSchema, + )] + #[serde(transparent)] + pub struct MulticastGroupIdentifier(pub ::std::string::String); + impl ::std::ops::Deref for MulticastGroupIdentifier { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } + } + + impl ::std::convert::From for ::std::string::String { + fn from(value: MulticastGroupIdentifier) -> Self { + value.0 + } + } + + impl ::std::convert::From<&MulticastGroupIdentifier> for MulticastGroupIdentifier { + fn from(value: &MulticastGroupIdentifier) -> Self { + value.clone() + } + } + + impl ::std::convert::From<::std::string::String> for MulticastGroupIdentifier { + fn from(value: ::std::string::String) -> Self { + Self(value) + } + } + + impl ::std::str::FromStr for MulticastGroupIdentifier { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } + } + + impl ::std::fmt::Display for MulticastGroupIdentifier { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } + } + + /// Specification for joining a multicast group with optional source + /// filtering. + /// + /// Used in `InstanceCreate` and `InstanceUpdate` to specify multicast group + /// membership along with per-member source IP configuration. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "Specification for joining a multicast group with + /// optional source filtering.\n\nUsed in `InstanceCreate` and + /// `InstanceUpdate` to specify multicast group membership along with + /// per-member source IP configuration.", /// "type": "object", /// "required": [ - /// "description", - /// "name" + /// "group" /// ], /// "properties": { - /// "description": { - /// "type": "string" - /// }, - /// "multicast_ip": { - /// "description": "The multicast IP address to allocate. If None, one - /// will be allocated from the default pool.", - /// "type": [ - /// "string", - /// "null" - /// ], - /// "format": "ip" - /// }, - /// "mvlan": { - /// "description": "Multicast VLAN (MVLAN) for egress multicast traffic - /// to upstream networks. Tags packets leaving the rack to traverse - /// VLAN-segmented upstream networks.\n\nValid range: 2-4094 (VLAN IDs 0-1 - /// are reserved by IEEE 802.1Q standard).", - /// "type": [ - /// "integer", - /// "null" - /// ], - /// "format": "uint16", - /// "minimum": 0.0 - /// }, - /// "name": { - /// "$ref": "#/components/schemas/Name" + /// "group": { + /// "description": "The multicast group to join, specified by name, + /// UUID, or IP address.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/MulticastGroupIdentifier" + /// } + /// ] /// }, - /// "pool": { - /// "description": "Name or ID of the IP pool to allocate from. If - /// None, uses the default multicast pool.", + /// "ip_version": { + /// "description": "IP version for pool selection when creating a group + /// by name. Required if both IPv4 and IPv6 default multicast pools are + /// linked.", /// "oneOf": [ /// { /// "type": "null" @@ -20458,17 +20806,16 @@ pub mod types { /// { /// "allOf": [ /// { - /// "$ref": "#/components/schemas/NameOrId" + /// "$ref": "#/components/schemas/IpVersion" /// } /// ] /// } /// ] /// }, /// "source_ips": { - /// "description": "Source IP addresses for Source-Specific Multicast - /// (SSM).\n\nNone uses default behavior (Any-Source Multicast). Empty list - /// explicitly allows any source (Any-Source Multicast). Non-empty list - /// restricts to specific sources (SSM).", + /// "description": "Source IPs for source-filtered multicast (SSM). + /// Optional for ASM groups, required for SSM groups (232.0.0.0/8, + /// ff3x::/32).", /// "type": [ /// "array", /// "null" @@ -20485,42 +20832,27 @@ pub mod types { #[derive( :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, )] - pub struct MulticastGroupCreate { - pub description: ::std::string::String, - /// The multicast IP address to allocate. If None, one will be allocated - /// from the default pool. + pub struct MulticastGroupJoinSpec { + /// The multicast group to join, specified by name, UUID, or IP address. + pub group: MulticastGroupIdentifier, + /// IP version for pool selection when creating a group by name. + /// Required if both IPv4 and IPv6 default multicast pools are linked. #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub multicast_ip: ::std::option::Option<::std::net::IpAddr>, - /// Multicast VLAN (MVLAN) for egress multicast traffic to upstream - /// networks. Tags packets leaving the rack to traverse VLAN-segmented - /// upstream networks. - /// - /// Valid range: 2-4094 (VLAN IDs 0-1 are reserved by IEEE 802.1Q - /// standard). - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub mvlan: ::std::option::Option, - pub name: Name, - /// Name or ID of the IP pool to allocate from. If None, uses the - /// default multicast pool. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub pool: ::std::option::Option, - /// Source IP addresses for Source-Specific Multicast (SSM). - /// - /// None uses default behavior (Any-Source Multicast). Empty list - /// explicitly allows any source (Any-Source Multicast). Non-empty list - /// restricts to specific sources (SSM). + pub ip_version: ::std::option::Option, + /// Source IPs for source-filtered multicast (SSM). Optional for ASM + /// groups, required for SSM groups (232.0.0.0/8, ff3x::/32). #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub source_ips: ::std::option::Option<::std::vec::Vec<::std::net::IpAddr>>, } - impl ::std::convert::From<&MulticastGroupCreate> for MulticastGroupCreate { - fn from(value: &MulticastGroupCreate) -> Self { + impl ::std::convert::From<&MulticastGroupJoinSpec> for MulticastGroupJoinSpec { + fn from(value: &MulticastGroupJoinSpec) -> Self { value.clone() } } - impl MulticastGroupCreate { - pub fn builder() -> builder::MulticastGroupCreate { + impl MulticastGroupJoinSpec { + pub fn builder() -> builder::MulticastGroupJoinSpec { Default::default() } } @@ -20540,7 +20872,9 @@ pub mod types { /// "id", /// "instance_id", /// "multicast_group_id", + /// "multicast_ip", /// "name", + /// "source_ips", /// "state", /// "time_created", /// "time_modified" @@ -20568,6 +20902,12 @@ pub mod types { /// "type": "string", /// "format": "uuid" /// }, + /// "multicast_ip": { + /// "description": "The multicast IP address of the group this member + /// belongs to.", + /// "type": "string", + /// "format": "ip" + /// }, /// "name": { /// "description": "unique, mutable, user-controlled identifier for /// each resource", @@ -20577,6 +20917,18 @@ pub mod types { /// } /// ] /// }, + /// "source_ips": { + /// "description": "Source IP addresses for this member's multicast + /// subscription.\n\n- **ASM**: Sources are optional. Empty array means any + /// source is allowed. Non-empty array enables source filtering + /// (IGMPv3/MLDv2). - **SSM**: Sources are required for SSM addresses + /// (232/8, ff3x::/32).", + /// "type": "array", + /// "items": { + /// "type": "string", + /// "format": "ip" + /// } + /// }, /// "state": { /// "description": "Current state of the multicast group membership.", /// "type": "string" @@ -20607,8 +20959,17 @@ pub mod types { pub instance_id: ::uuid::Uuid, /// The ID of the multicast group this member belongs to. pub multicast_group_id: ::uuid::Uuid, + /// The multicast IP address of the group this member belongs to. + pub multicast_ip: ::std::net::IpAddr, /// unique, mutable, user-controlled identifier for each resource pub name: Name, + /// Source IP addresses for this member's multicast subscription. + /// + /// - **ASM**: Sources are optional. Empty array means any source is + /// allowed. Non-empty array enables source filtering (IGMPv3/MLDv2). + /// - **SSM**: Sources are required for SSM addresses (232/8, + /// ff3x::/32). + pub source_ips: ::std::vec::Vec<::std::net::IpAddr>, /// Current state of the multicast group membership. pub state: ::std::string::String, /// timestamp when this resource was created @@ -20629,52 +20990,6 @@ pub mod types { } } - /// Parameters for adding an instance to a multicast group. - /// - ///
JSON schema - /// - /// ```json - /// { - /// "description": "Parameters for adding an instance to a multicast - /// group.", - /// "type": "object", - /// "required": [ - /// "instance" - /// ], - /// "properties": { - /// "instance": { - /// "description": "Name or ID of the instance to add to the multicast - /// group", - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/NameOrId" - /// } - /// ] - /// } - /// } - /// } - /// ``` - ///
- #[derive( - :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, - )] - pub struct MulticastGroupMemberAdd { - /// Name or ID of the instance to add to the multicast group - pub instance: NameOrId, - } - - impl ::std::convert::From<&MulticastGroupMemberAdd> for MulticastGroupMemberAdd { - fn from(value: &MulticastGroupMemberAdd) -> Self { - value.clone() - } - } - - impl MulticastGroupMemberAdd { - pub fn builder() -> builder::MulticastGroupMemberAdd { - Default::default() - } - } - /// A single page of results /// ///
JSON schema @@ -20783,100 +21098,6 @@ pub mod types { } } - /// Update-time parameters for a multicast group. - /// - ///
JSON schema - /// - /// ```json - /// { - /// "description": "Update-time parameters for a multicast group.", - /// "type": "object", - /// "properties": { - /// "description": { - /// "type": [ - /// "string", - /// "null" - /// ] - /// }, - /// "mvlan": { - /// "description": "Multicast VLAN (MVLAN) for egress multicast traffic - /// to upstream networks. Set to null to clear the MVLAN. Valid range: - /// 2-4094 when provided. Omit the field to leave mvlan unchanged.", - /// "type": [ - /// "integer", - /// "null" - /// ], - /// "format": "uint16", - /// "minimum": 0.0 - /// }, - /// "name": { - /// "oneOf": [ - /// { - /// "type": "null" - /// }, - /// { - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/Name" - /// } - /// ] - /// } - /// ] - /// }, - /// "source_ips": { - /// "type": [ - /// "array", - /// "null" - /// ], - /// "items": { - /// "type": "string", - /// "format": "ip" - /// } - /// } - /// } - /// } - /// ``` - ///
- #[derive( - :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, - )] - pub struct MulticastGroupUpdate { - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub description: ::std::option::Option<::std::string::String>, - /// Multicast VLAN (MVLAN) for egress multicast traffic to upstream - /// networks. Set to null to clear the MVLAN. Valid range: 2-4094 when - /// provided. Omit the field to leave mvlan unchanged. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub mvlan: ::std::option::Option, - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub name: ::std::option::Option, - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub source_ips: ::std::option::Option<::std::vec::Vec<::std::net::IpAddr>>, - } - - impl ::std::convert::From<&MulticastGroupUpdate> for MulticastGroupUpdate { - fn from(value: &MulticastGroupUpdate) -> Self { - value.clone() - } - } - - impl ::std::default::Default for MulticastGroupUpdate { - fn default() -> Self { - Self { - description: Default::default(), - mvlan: Default::default(), - name: Default::default(), - source_ips: Default::default(), - } - } - } - - impl MulticastGroupUpdate { - pub fn builder() -> builder::MulticastGroupUpdate { - Default::default() - } - } - /// Names must begin with a lower case ASCII letter, be composed exclusively /// of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end /// with a '-'. Names cannot be a UUID, but they may contain a UUID. They @@ -21375,13 +21596,12 @@ pub mod types { /// "type": "object", /// "required": [ /// "id", - /// "ip", + /// "ip_config", /// "kind", /// "mac", /// "name", /// "primary", /// "slot", - /// "subnet", /// "vni" /// ], /// "properties": { @@ -21389,9 +21609,8 @@ pub mod types { /// "type": "string", /// "format": "uuid" /// }, - /// "ip": { - /// "type": "string", - /// "format": "ip" + /// "ip_config": { + /// "$ref": "#/components/schemas/PrivateIpConfig" /// }, /// "kind": { /// "$ref": "#/components/schemas/NetworkInterfaceKind" @@ -21410,16 +21629,6 @@ pub mod types { /// "format": "uint8", /// "minimum": 0.0 /// }, - /// "subnet": { - /// "$ref": "#/components/schemas/IpNet" - /// }, - /// "transit_ips": { - /// "default": [], - /// "type": "array", - /// "items": { - /// "$ref": "#/components/schemas/IpNet" - /// } - /// }, /// "vni": { /// "$ref": "#/components/schemas/Vni" /// } @@ -21432,15 +21641,12 @@ pub mod types { )] pub struct NetworkInterface { pub id: ::uuid::Uuid, - pub ip: ::std::net::IpAddr, + pub ip_config: PrivateIpConfig, pub kind: NetworkInterfaceKind, pub mac: MacAddr, pub name: Name, pub primary: bool, pub slot: u8, - pub subnet: IpNet, - #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] - pub transit_ips: ::std::vec::Vec, pub vni: Vni, } @@ -22502,6 +22708,819 @@ pub mod types { } } + /// Specify which IP pool to allocate from. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "Specify which IP pool to allocate from.", + /// "oneOf": [ + /// { + /// "description": "Use the specified pool by name or ID.", + /// "type": "object", + /// "required": [ + /// "pool", + /// "type" + /// ], + /// "properties": { + /// "pool": { + /// "description": "The pool to allocate from.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/NameOrId" + /// } + /// ] + /// }, + /// "type": { + /// "type": "string", + /// "enum": [ + /// "explicit" + /// ] + /// } + /// } + /// }, + /// { + /// "description": "Use the default pool for the silo.", + /// "type": "object", + /// "required": [ + /// "type" + /// ], + /// "properties": { + /// "ip_version": { + /// "description": "IP version to use when multiple default pools exist. Required if both IPv4 and IPv6 default pools are configured.", + /// "oneOf": [ + /// { + /// "type": "null" + /// }, + /// { + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/IpVersion" + /// } + /// ] + /// } + /// ] + /// }, + /// "type": { + /// "type": "string", + /// "enum": [ + /// "auto" + /// ] + /// } + /// } + /// } + /// ] + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + #[serde(tag = "type")] + pub enum PoolSelector { + /// Use the specified pool by name or ID. + #[serde(rename = "explicit")] + Explicit { + /// The pool to allocate from. + pool: NameOrId, + }, + /// Use the default pool for the silo. + #[serde(rename = "auto")] + Auto { + /// IP version to use when multiple default pools exist. Required if + /// both IPv4 and IPv6 default pools are configured. + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + ip_version: ::std::option::Option, + }, + } + + impl ::std::convert::From<&Self> for PoolSelector { + fn from(value: &PoolSelector) -> Self { + value.clone() + } + } + + /// VPC-private IP address configuration for a network interface. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "VPC-private IP address configuration for a network + /// interface.", + /// "oneOf": [ + /// { + /// "description": "The interface has only an IPv4 configuration.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "v4" + /// ] + /// }, + /// "value": { + /// "$ref": "#/components/schemas/PrivateIpv4Config" + /// } + /// } + /// }, + /// { + /// "description": "The interface has only an IPv6 configuration.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "v6" + /// ] + /// }, + /// "value": { + /// "$ref": "#/components/schemas/PrivateIpv6Config" + /// } + /// } + /// }, + /// { + /// "description": "The interface is dual-stack.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "dual_stack" + /// ] + /// }, + /// "value": { + /// "type": "object", + /// "required": [ + /// "v4", + /// "v6" + /// ], + /// "properties": { + /// "v4": { + /// "description": "The interface's IPv4 configuration.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/PrivateIpv4Config" + /// } + /// ] + /// }, + /// "v6": { + /// "description": "The interface's IPv6 configuration.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/PrivateIpv6Config" + /// } + /// ] + /// } + /// } + /// } + /// } + /// } + /// ] + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + #[serde(tag = "type", content = "value")] + pub enum PrivateIpConfig { + /// The interface has only an IPv4 configuration. + #[serde(rename = "v4")] + V4(PrivateIpv4Config), + /// The interface has only an IPv6 configuration. + #[serde(rename = "v6")] + V6(PrivateIpv6Config), + /// The interface is dual-stack. + #[serde(rename = "dual_stack")] + DualStack { + /// The interface's IPv4 configuration. + v4: PrivateIpv4Config, + /// The interface's IPv6 configuration. + v6: PrivateIpv6Config, + }, + } + + impl ::std::convert::From<&Self> for PrivateIpConfig { + fn from(value: &PrivateIpConfig) -> Self { + value.clone() + } + } + + impl ::std::convert::From for PrivateIpConfig { + fn from(value: PrivateIpv4Config) -> Self { + Self::V4(value) + } + } + + impl ::std::convert::From for PrivateIpConfig { + fn from(value: PrivateIpv6Config) -> Self { + Self::V6(value) + } + } + + /// The VPC-private IP stack for a network interface. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "The VPC-private IP stack for a network interface.", + /// "oneOf": [ + /// { + /// "description": "The interface has only an IPv4 stack.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "v4" + /// ] + /// }, + /// "value": { + /// "$ref": "#/components/schemas/PrivateIpv4Stack" + /// } + /// } + /// }, + /// { + /// "description": "The interface has only an IPv6 stack.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "v6" + /// ] + /// }, + /// "value": { + /// "$ref": "#/components/schemas/PrivateIpv6Stack" + /// } + /// } + /// }, + /// { + /// "description": "The interface is dual-stack IPv4 and IPv6.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "dual_stack" + /// ] + /// }, + /// "value": { + /// "type": "object", + /// "required": [ + /// "v4", + /// "v6" + /// ], + /// "properties": { + /// "v4": { + /// "$ref": "#/components/schemas/PrivateIpv4Stack" + /// }, + /// "v6": { + /// "$ref": "#/components/schemas/PrivateIpv6Stack" + /// } + /// } + /// } + /// } + /// } + /// ] + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + #[serde(tag = "type", content = "value")] + pub enum PrivateIpStack { + /// The interface has only an IPv4 stack. + #[serde(rename = "v4")] + V4(PrivateIpv4Stack), + /// The interface has only an IPv6 stack. + #[serde(rename = "v6")] + V6(PrivateIpv6Stack), + /// The interface is dual-stack IPv4 and IPv6. + #[serde(rename = "dual_stack")] + DualStack { + v4: PrivateIpv4Stack, + v6: PrivateIpv6Stack, + }, + } + + impl ::std::convert::From<&Self> for PrivateIpStack { + fn from(value: &PrivateIpStack) -> Self { + value.clone() + } + } + + impl ::std::convert::From for PrivateIpStack { + fn from(value: PrivateIpv4Stack) -> Self { + Self::V4(value) + } + } + + impl ::std::convert::From for PrivateIpStack { + fn from(value: PrivateIpv6Stack) -> Self { + Self::V6(value) + } + } + + /// Create parameters for a network interface's IP stack. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "Create parameters for a network interface's IP stack.", + /// "oneOf": [ + /// { + /// "description": "The interface has only an IPv4 stack.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "v4" + /// ] + /// }, + /// "value": { + /// "$ref": "#/components/schemas/PrivateIpv4StackCreate" + /// } + /// } + /// }, + /// { + /// "description": "The interface has only an IPv6 stack.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "v6" + /// ] + /// }, + /// "value": { + /// "$ref": "#/components/schemas/PrivateIpv6StackCreate" + /// } + /// } + /// }, + /// { + /// "description": "The interface has both an IPv4 and IPv6 stack.", + /// "type": "object", + /// "required": [ + /// "type", + /// "value" + /// ], + /// "properties": { + /// "type": { + /// "type": "string", + /// "enum": [ + /// "dual_stack" + /// ] + /// }, + /// "value": { + /// "type": "object", + /// "required": [ + /// "v4", + /// "v6" + /// ], + /// "properties": { + /// "v4": { + /// "$ref": "#/components/schemas/PrivateIpv4StackCreate" + /// }, + /// "v6": { + /// "$ref": "#/components/schemas/PrivateIpv6StackCreate" + /// } + /// } + /// } + /// } + /// } + /// ] + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + #[serde(tag = "type", content = "value")] + pub enum PrivateIpStackCreate { + /// The interface has only an IPv4 stack. + #[serde(rename = "v4")] + V4(PrivateIpv4StackCreate), + /// The interface has only an IPv6 stack. + #[serde(rename = "v6")] + V6(PrivateIpv6StackCreate), + /// The interface has both an IPv4 and IPv6 stack. + #[serde(rename = "dual_stack")] + DualStack { + v4: PrivateIpv4StackCreate, + v6: PrivateIpv6StackCreate, + }, + } + + impl ::std::convert::From<&Self> for PrivateIpStackCreate { + fn from(value: &PrivateIpStackCreate) -> Self { + value.clone() + } + } + + impl ::std::convert::From for PrivateIpStackCreate { + fn from(value: PrivateIpv4StackCreate) -> Self { + Self::V4(value) + } + } + + impl ::std::convert::From for PrivateIpStackCreate { + fn from(value: PrivateIpv6StackCreate) -> Self { + Self::V6(value) + } + } + + /// VPC-private IPv4 configuration for a network interface. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "VPC-private IPv4 configuration for a network + /// interface.", + /// "type": "object", + /// "required": [ + /// "ip", + /// "subnet" + /// ], + /// "properties": { + /// "ip": { + /// "description": "VPC-private IP address.", + /// "type": "string", + /// "format": "ipv4" + /// }, + /// "subnet": { + /// "description": "The IP subnet.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/Ipv4Net" + /// } + /// ] + /// }, + /// "transit_ips": { + /// "description": "Additional networks on which the interface can send + /// / receive traffic.", + /// "default": [], + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/Ipv4Net" + /// } + /// } + /// } + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + pub struct PrivateIpv4Config { + /// VPC-private IP address. + pub ip: ::std::net::Ipv4Addr, + /// The IP subnet. + pub subnet: Ipv4Net, + /// Additional networks on which the interface can send / receive + /// traffic. + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub transit_ips: ::std::vec::Vec, + } + + impl ::std::convert::From<&PrivateIpv4Config> for PrivateIpv4Config { + fn from(value: &PrivateIpv4Config) -> Self { + value.clone() + } + } + + impl PrivateIpv4Config { + pub fn builder() -> builder::PrivateIpv4Config { + Default::default() + } + } + + /// The VPC-private IPv4 stack for a network interface + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "The VPC-private IPv4 stack for a network interface", + /// "type": "object", + /// "required": [ + /// "ip", + /// "transit_ips" + /// ], + /// "properties": { + /// "ip": { + /// "description": "The VPC-private IPv4 address for the interface.", + /// "type": "string", + /// "format": "ipv4" + /// }, + /// "transit_ips": { + /// "description": "A set of additional IPv4 networks that this + /// interface may send and receive traffic on.", + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/Ipv4Net" + /// } + /// } + /// } + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + pub struct PrivateIpv4Stack { + /// The VPC-private IPv4 address for the interface. + pub ip: ::std::net::Ipv4Addr, + /// A set of additional IPv4 networks that this interface may send and + /// receive traffic on. + pub transit_ips: ::std::vec::Vec, + } + + impl ::std::convert::From<&PrivateIpv4Stack> for PrivateIpv4Stack { + fn from(value: &PrivateIpv4Stack) -> Self { + value.clone() + } + } + + impl PrivateIpv4Stack { + pub fn builder() -> builder::PrivateIpv4Stack { + Default::default() + } + } + + /// Configuration for a network interface's IPv4 addressing. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "Configuration for a network interface's IPv4 + /// addressing.", + /// "type": "object", + /// "required": [ + /// "ip" + /// ], + /// "properties": { + /// "ip": { + /// "description": "The VPC-private address to assign to the + /// interface.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/Ipv4Assignment" + /// } + /// ] + /// }, + /// "transit_ips": { + /// "description": "Additional IP networks the interface can send / + /// receive on.", + /// "default": [], + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/Ipv4Net" + /// } + /// } + /// } + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + pub struct PrivateIpv4StackCreate { + /// The VPC-private address to assign to the interface. + pub ip: Ipv4Assignment, + /// Additional IP networks the interface can send / receive on. + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub transit_ips: ::std::vec::Vec, + } + + impl ::std::convert::From<&PrivateIpv4StackCreate> for PrivateIpv4StackCreate { + fn from(value: &PrivateIpv4StackCreate) -> Self { + value.clone() + } + } + + impl PrivateIpv4StackCreate { + pub fn builder() -> builder::PrivateIpv4StackCreate { + Default::default() + } + } + + /// VPC-private IPv6 configuration for a network interface. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "VPC-private IPv6 configuration for a network + /// interface.", + /// "type": "object", + /// "required": [ + /// "ip", + /// "subnet", + /// "transit_ips" + /// ], + /// "properties": { + /// "ip": { + /// "description": "VPC-private IP address.", + /// "type": "string", + /// "format": "ipv6" + /// }, + /// "subnet": { + /// "description": "The IP subnet.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/Ipv6Net" + /// } + /// ] + /// }, + /// "transit_ips": { + /// "description": "Additional networks on which the interface can send + /// / receive traffic.", + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/Ipv6Net" + /// } + /// } + /// } + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + pub struct PrivateIpv6Config { + /// VPC-private IP address. + pub ip: ::std::net::Ipv6Addr, + /// The IP subnet. + pub subnet: Ipv6Net, + /// Additional networks on which the interface can send / receive + /// traffic. + pub transit_ips: ::std::vec::Vec, + } + + impl ::std::convert::From<&PrivateIpv6Config> for PrivateIpv6Config { + fn from(value: &PrivateIpv6Config) -> Self { + value.clone() + } + } + + impl PrivateIpv6Config { + pub fn builder() -> builder::PrivateIpv6Config { + Default::default() + } + } + + /// The VPC-private IPv6 stack for a network interface + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "The VPC-private IPv6 stack for a network interface", + /// "type": "object", + /// "required": [ + /// "ip", + /// "transit_ips" + /// ], + /// "properties": { + /// "ip": { + /// "description": "The VPC-private IPv6 address for the interface.", + /// "type": "string", + /// "format": "ipv6" + /// }, + /// "transit_ips": { + /// "description": "A set of additional IPv6 networks that this + /// interface may send and receive traffic on.", + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/Ipv6Net" + /// } + /// } + /// } + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + pub struct PrivateIpv6Stack { + /// The VPC-private IPv6 address for the interface. + pub ip: ::std::net::Ipv6Addr, + /// A set of additional IPv6 networks that this interface may send and + /// receive traffic on. + pub transit_ips: ::std::vec::Vec, + } + + impl ::std::convert::From<&PrivateIpv6Stack> for PrivateIpv6Stack { + fn from(value: &PrivateIpv6Stack) -> Self { + value.clone() + } + } + + impl PrivateIpv6Stack { + pub fn builder() -> builder::PrivateIpv6Stack { + Default::default() + } + } + + /// Configuration for a network interface's IPv6 addressing. + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "Configuration for a network interface's IPv6 + /// addressing.", + /// "type": "object", + /// "required": [ + /// "ip" + /// ], + /// "properties": { + /// "ip": { + /// "description": "The VPC-private address to assign to the + /// interface.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/Ipv6Assignment" + /// } + /// ] + /// }, + /// "transit_ips": { + /// "description": "Additional IP networks the interface can send / + /// receive on.", + /// "default": [], + /// "type": "array", + /// "items": { + /// "$ref": "#/components/schemas/Ipv6Net" + /// } + /// } + /// } + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + pub struct PrivateIpv6StackCreate { + /// The VPC-private address to assign to the interface. + pub ip: Ipv6Assignment, + /// Additional IP networks the interface can send / receive on. + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub transit_ips: ::std::vec::Vec, + } + + impl ::std::convert::From<&PrivateIpv6StackCreate> for PrivateIpv6StackCreate { + fn from(value: &PrivateIpv6StackCreate) -> Self { + value.clone() + } + } + + impl PrivateIpv6StackCreate { + pub fn builder() -> builder::PrivateIpv6StackCreate { + Default::default() + } + } + /// Identity-related metadata that's included in nearly all public API /// objects /// @@ -22604,23 +23623,21 @@ pub mod types { /// "description": { /// "type": "string" /// }, - /// "ip_pool": { - /// "oneOf": [ - /// { - /// "type": "null" - /// }, + /// "name": { + /// "$ref": "#/components/schemas/Name" + /// }, + /// "pool_selector": { + /// "description": "Pool to allocate from.", + /// "default": { + /// "ip_version": null, + /// "type": "auto" + /// }, + /// "allOf": [ /// { - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/NameOrId" - /// } - /// ] + /// "$ref": "#/components/schemas/PoolSelector" /// } /// ] /// }, - /// "name": { - /// "$ref": "#/components/schemas/Name" - /// }, /// "sled": { /// "type": "string", /// "format": "uuid" @@ -22634,9 +23651,10 @@ pub mod types { )] pub struct ProbeCreate { pub description: ::std::string::String, - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub ip_pool: ::std::option::Option, pub name: Name, + /// Pool to allocate from. + #[serde(default = "defaults::probe_create_pool_selector")] + pub pool_selector: PoolSelector, pub sled: ::uuid::Uuid, } @@ -43045,44 +44063,26 @@ pub mod types { #[derive(Clone, Debug)] pub struct EphemeralIpCreate { - ip_version: ::std::result::Result< - ::std::option::Option, - ::std::string::String, - >, - pool: ::std::result::Result< - ::std::option::Option, - ::std::string::String, - >, + pool_selector: ::std::result::Result, } impl ::std::default::Default for EphemeralIpCreate { fn default() -> Self { Self { - ip_version: Ok(Default::default()), - pool: Ok(Default::default()), + pool_selector: Ok(super::defaults::ephemeral_ip_create_pool_selector()), } } } impl EphemeralIpCreate { - pub fn ip_version(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::option::Option>, - T::Error: ::std::fmt::Display, - { - self.ip_version = value - .try_into() - .map_err(|e| format!("error converting supplied value for ip_version: {}", e)); - self - } - pub fn pool(mut self, value: T) -> Self + pub fn pool_selector(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::option::Option>, + T: ::std::convert::TryInto, T::Error: ::std::fmt::Display, { - self.pool = value - .try_into() - .map_err(|e| format!("error converting supplied value for pool: {}", e)); + self.pool_selector = value.try_into().map_err(|e| { + format!("error converting supplied value for pool_selector: {}", e) + }); self } } @@ -43093,8 +44093,7 @@ pub mod types { value: EphemeralIpCreate, ) -> ::std::result::Result { Ok(Self { - ip_version: value.ip_version?, - pool: value.pool?, + pool_selector: value.pool_selector?, }) } } @@ -43102,8 +44101,7 @@ pub mod types { impl ::std::convert::From for EphemeralIpCreate { fn from(value: super::EphemeralIpCreate) -> Self { Self { - ip_version: Ok(value.ip_version), - pool: Ok(value.pool), + pool_selector: Ok(value.pool_selector), } } } @@ -43728,63 +44726,43 @@ pub mod types { #[derive(Clone, Debug)] pub struct FloatingIpCreate { + address_selector: ::std::result::Result, description: ::std::result::Result<::std::string::String, ::std::string::String>, - ip: ::std::result::Result< - ::std::option::Option<::std::net::IpAddr>, - ::std::string::String, - >, - ip_version: ::std::result::Result< - ::std::option::Option, - ::std::string::String, - >, name: ::std::result::Result, - pool: ::std::result::Result< - ::std::option::Option, - ::std::string::String, - >, } impl ::std::default::Default for FloatingIpCreate { fn default() -> Self { Self { + address_selector: Ok(super::defaults::floating_ip_create_address_selector()), description: Err("no value supplied for description".to_string()), - ip: Ok(Default::default()), - ip_version: Ok(Default::default()), name: Err("no value supplied for name".to_string()), - pool: Ok(Default::default()), } } } impl FloatingIpCreate { - pub fn description(mut self, value: T) -> Self + pub fn address_selector(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::string::String>, - T::Error: ::std::fmt::Display, - { - self.description = value - .try_into() - .map_err(|e| format!("error converting supplied value for description: {}", e)); - self - } - pub fn ip(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::option::Option<::std::net::IpAddr>>, + T: ::std::convert::TryInto, T::Error: ::std::fmt::Display, { - self.ip = value - .try_into() - .map_err(|e| format!("error converting supplied value for ip: {}", e)); + self.address_selector = value.try_into().map_err(|e| { + format!( + "error converting supplied value for address_selector: {}", + e + ) + }); self } - pub fn ip_version(mut self, value: T) -> Self + pub fn description(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::option::Option>, + T: ::std::convert::TryInto<::std::string::String>, T::Error: ::std::fmt::Display, { - self.ip_version = value + self.description = value .try_into() - .map_err(|e| format!("error converting supplied value for ip_version: {}", e)); + .map_err(|e| format!("error converting supplied value for description: {}", e)); self } pub fn name(mut self, value: T) -> Self @@ -43797,16 +44775,6 @@ pub mod types { .map_err(|e| format!("error converting supplied value for name: {}", e)); self } - pub fn pool(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::option::Option>, - T::Error: ::std::fmt::Display, - { - self.pool = value - .try_into() - .map_err(|e| format!("error converting supplied value for pool: {}", e)); - self - } } impl ::std::convert::TryFrom for super::FloatingIpCreate { @@ -43815,11 +44783,9 @@ pub mod types { value: FloatingIpCreate, ) -> ::std::result::Result { Ok(Self { + address_selector: value.address_selector?, description: value.description?, - ip: value.ip?, - ip_version: value.ip_version?, name: value.name?, - pool: value.pool?, }) } } @@ -43827,11 +44793,9 @@ pub mod types { impl ::std::convert::From for FloatingIpCreate { fn from(value: super::FloatingIpCreate) -> Self { Self { + address_selector: Ok(value.address_selector), description: Ok(value.description), - ip: Ok(value.ip), - ip_version: Ok(value.ip_version), name: Ok(value.name), - pool: Ok(value.pool), } } } @@ -46784,8 +47748,10 @@ pub mod types { >, hostname: ::std::result::Result, memory: ::std::result::Result, - multicast_groups: - ::std::result::Result<::std::vec::Vec, ::std::string::String>, + multicast_groups: ::std::result::Result< + ::std::vec::Vec, + ::std::string::String, + >, name: ::std::result::Result, ncpus: ::std::result::Result, network_interfaces: ::std::result::Result< @@ -46922,7 +47888,7 @@ pub mod types { } pub fn multicast_groups(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::vec::Vec>, + T: ::std::convert::TryInto<::std::vec::Vec>, T::Error: ::std::fmt::Display, { self.multicast_groups = value.try_into().map_err(|e| { @@ -47047,12 +48013,79 @@ pub mod types { } } + #[derive(Clone, Debug)] + pub struct InstanceMulticastGroupJoin { + ip_version: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + source_ips: ::std::result::Result< + ::std::option::Option<::std::vec::Vec<::std::net::IpAddr>>, + ::std::string::String, + >, + } + + impl ::std::default::Default for InstanceMulticastGroupJoin { + fn default() -> Self { + Self { + ip_version: Ok(Default::default()), + source_ips: Ok(Default::default()), + } + } + } + + impl InstanceMulticastGroupJoin { + pub fn ip_version(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.ip_version = value + .try_into() + .map_err(|e| format!("error converting supplied value for ip_version: {}", e)); + self + } + pub fn source_ips(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option<::std::vec::Vec<::std::net::IpAddr>>, + >, + T::Error: ::std::fmt::Display, + { + self.source_ips = value + .try_into() + .map_err(|e| format!("error converting supplied value for source_ips: {}", e)); + self + } + } + + impl ::std::convert::TryFrom for super::InstanceMulticastGroupJoin { + type Error = super::error::ConversionError; + fn try_from( + value: InstanceMulticastGroupJoin, + ) -> ::std::result::Result { + Ok(Self { + ip_version: value.ip_version?, + source_ips: value.source_ips?, + }) + } + } + + impl ::std::convert::From for InstanceMulticastGroupJoin { + fn from(value: super::InstanceMulticastGroupJoin) -> Self { + Self { + ip_version: Ok(value.ip_version), + source_ips: Ok(value.source_ips), + } + } + } + #[derive(Clone, Debug)] pub struct InstanceNetworkInterface { description: ::std::result::Result<::std::string::String, ::std::string::String>, id: ::std::result::Result<::uuid::Uuid, ::std::string::String>, instance_id: ::std::result::Result<::uuid::Uuid, ::std::string::String>, - ip: ::std::result::Result<::std::net::IpAddr, ::std::string::String>, + ip_stack: ::std::result::Result, mac: ::std::result::Result, name: ::std::result::Result, primary: ::std::result::Result, @@ -47065,8 +48098,6 @@ pub mod types { ::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String, >, - transit_ips: - ::std::result::Result<::std::vec::Vec, ::std::string::String>, vpc_id: ::std::result::Result<::uuid::Uuid, ::std::string::String>, } @@ -47076,14 +48107,13 @@ pub mod types { description: Err("no value supplied for description".to_string()), id: Err("no value supplied for id".to_string()), instance_id: Err("no value supplied for instance_id".to_string()), - ip: Err("no value supplied for ip".to_string()), + ip_stack: Err("no value supplied for ip_stack".to_string()), mac: Err("no value supplied for mac".to_string()), name: Err("no value supplied for name".to_string()), primary: Err("no value supplied for primary".to_string()), subnet_id: Err("no value supplied for subnet_id".to_string()), time_created: Err("no value supplied for time_created".to_string()), time_modified: Err("no value supplied for time_modified".to_string()), - transit_ips: Ok(Default::default()), vpc_id: Err("no value supplied for vpc_id".to_string()), } } @@ -47120,14 +48150,14 @@ pub mod types { .map_err(|e| format!("error converting supplied value for instance_id: {}", e)); self } - pub fn ip(mut self, value: T) -> Self + pub fn ip_stack(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::net::IpAddr>, + T: ::std::convert::TryInto, T::Error: ::std::fmt::Display, { - self.ip = value + self.ip_stack = value .try_into() - .map_err(|e| format!("error converting supplied value for ip: {}", e)); + .map_err(|e| format!("error converting supplied value for ip_stack: {}", e)); self } pub fn mac(mut self, value: T) -> Self @@ -47190,16 +48220,6 @@ pub mod types { }); self } - pub fn transit_ips(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::vec::Vec>, - T::Error: ::std::fmt::Display, - { - self.transit_ips = value - .try_into() - .map_err(|e| format!("error converting supplied value for transit_ips: {}", e)); - self - } pub fn vpc_id(mut self, value: T) -> Self where T: ::std::convert::TryInto<::uuid::Uuid>, @@ -47221,14 +48241,13 @@ pub mod types { description: value.description?, id: value.id?, instance_id: value.instance_id?, - ip: value.ip?, + ip_stack: value.ip_stack?, mac: value.mac?, name: value.name?, primary: value.primary?, subnet_id: value.subnet_id?, time_created: value.time_created?, time_modified: value.time_modified?, - transit_ips: value.transit_ips?, vpc_id: value.vpc_id?, }) } @@ -47240,14 +48259,13 @@ pub mod types { description: Ok(value.description), id: Ok(value.id), instance_id: Ok(value.instance_id), - ip: Ok(value.ip), + ip_stack: Ok(value.ip_stack), mac: Ok(value.mac), name: Ok(value.name), primary: Ok(value.primary), subnet_id: Ok(value.subnet_id), time_created: Ok(value.time_created), time_modified: Ok(value.time_modified), - transit_ips: Ok(value.transit_ips), vpc_id: Ok(value.vpc_id), } } @@ -47256,14 +48274,9 @@ pub mod types { #[derive(Clone, Debug)] pub struct InstanceNetworkInterfaceCreate { description: ::std::result::Result<::std::string::String, ::std::string::String>, - ip: ::std::result::Result< - ::std::option::Option<::std::net::IpAddr>, - ::std::string::String, - >, + ip_config: ::std::result::Result, name: ::std::result::Result, subnet_name: ::std::result::Result, - transit_ips: - ::std::result::Result<::std::vec::Vec, ::std::string::String>, vpc_name: ::std::result::Result, } @@ -47271,10 +48284,9 @@ pub mod types { fn default() -> Self { Self { description: Err("no value supplied for description".to_string()), - ip: Ok(Default::default()), + ip_config: Ok(super::defaults::instance_network_interface_create_ip_config()), name: Err("no value supplied for name".to_string()), subnet_name: Err("no value supplied for subnet_name".to_string()), - transit_ips: Ok(Default::default()), vpc_name: Err("no value supplied for vpc_name".to_string()), } } @@ -47291,14 +48303,14 @@ pub mod types { .map_err(|e| format!("error converting supplied value for description: {}", e)); self } - pub fn ip(mut self, value: T) -> Self + pub fn ip_config(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::option::Option<::std::net::IpAddr>>, + T: ::std::convert::TryInto, T::Error: ::std::fmt::Display, { - self.ip = value + self.ip_config = value .try_into() - .map_err(|e| format!("error converting supplied value for ip: {}", e)); + .map_err(|e| format!("error converting supplied value for ip_config: {}", e)); self } pub fn name(mut self, value: T) -> Self @@ -47321,16 +48333,6 @@ pub mod types { .map_err(|e| format!("error converting supplied value for subnet_name: {}", e)); self } - pub fn transit_ips(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::vec::Vec>, - T::Error: ::std::fmt::Display, - { - self.transit_ips = value - .try_into() - .map_err(|e| format!("error converting supplied value for transit_ips: {}", e)); - self - } pub fn vpc_name(mut self, value: T) -> Self where T: ::std::convert::TryInto, @@ -47352,10 +48354,9 @@ pub mod types { ) -> ::std::result::Result { Ok(Self { description: value.description?, - ip: value.ip?, + ip_config: value.ip_config?, name: value.name?, subnet_name: value.subnet_name?, - transit_ips: value.transit_ips?, vpc_name: value.vpc_name?, }) } @@ -47367,10 +48368,9 @@ pub mod types { fn from(value: super::InstanceNetworkInterfaceCreate) -> Self { Self { description: Ok(value.description), - ip: Ok(value.ip), + ip_config: Ok(value.ip_config), name: Ok(value.name), subnet_name: Ok(value.subnet_name), - transit_ips: Ok(value.transit_ips), vpc_name: Ok(value.vpc_name), } } @@ -47680,7 +48680,7 @@ pub mod types { >, memory: ::std::result::Result, multicast_groups: ::std::result::Result< - ::std::option::Option<::std::vec::Vec>, + ::std::option::Option<::std::vec::Vec>, ::std::string::String, >, ncpus: ::std::result::Result, @@ -47747,7 +48747,9 @@ pub mod types { } pub fn multicast_groups(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::option::Option<::std::vec::Vec>>, + T: ::std::convert::TryInto< + ::std::option::Option<::std::vec::Vec>, + >, T::Error: ::std::fmt::Display, { self.multicast_groups = value.try_into().map_err(|e| { @@ -50957,16 +51959,10 @@ pub mod types { } #[derive(Clone, Debug)] - pub struct MulticastGroupCreate { - description: ::std::result::Result<::std::string::String, ::std::string::String>, - multicast_ip: ::std::result::Result< - ::std::option::Option<::std::net::IpAddr>, - ::std::string::String, - >, - mvlan: ::std::result::Result<::std::option::Option, ::std::string::String>, - name: ::std::result::Result, - pool: ::std::result::Result< - ::std::option::Option, + pub struct MulticastGroupJoinSpec { + group: ::std::result::Result, + ip_version: ::std::result::Result< + ::std::option::Option, ::std::string::String, >, source_ips: ::std::result::Result< @@ -50975,68 +51971,35 @@ pub mod types { >, } - impl ::std::default::Default for MulticastGroupCreate { + impl ::std::default::Default for MulticastGroupJoinSpec { fn default() -> Self { Self { - description: Err("no value supplied for description".to_string()), - multicast_ip: Ok(Default::default()), - mvlan: Ok(Default::default()), - name: Err("no value supplied for name".to_string()), - pool: Ok(Default::default()), + group: Err("no value supplied for group".to_string()), + ip_version: Ok(Default::default()), source_ips: Ok(Default::default()), } } } - impl MulticastGroupCreate { - pub fn description(mut self, value: T) -> Self + impl MulticastGroupJoinSpec { + pub fn group(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::string::String>, + T: ::std::convert::TryInto, T::Error: ::std::fmt::Display, { - self.description = value + self.group = value .try_into() - .map_err(|e| format!("error converting supplied value for description: {}", e)); + .map_err(|e| format!("error converting supplied value for group: {}", e)); self } - pub fn multicast_ip(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::option::Option<::std::net::IpAddr>>, - T::Error: ::std::fmt::Display, - { - self.multicast_ip = value.try_into().map_err(|e| { - format!("error converting supplied value for multicast_ip: {}", e) - }); - self - } - pub fn mvlan(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::option::Option>, - T::Error: ::std::fmt::Display, - { - self.mvlan = value - .try_into() - .map_err(|e| format!("error converting supplied value for mvlan: {}", e)); - self - } - pub fn name(mut self, value: T) -> Self - where - T: ::std::convert::TryInto, - T::Error: ::std::fmt::Display, - { - self.name = value - .try_into() - .map_err(|e| format!("error converting supplied value for name: {}", e)); - self - } - pub fn pool(mut self, value: T) -> Self + pub fn ip_version(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::option::Option>, + T: ::std::convert::TryInto<::std::option::Option>, T::Error: ::std::fmt::Display, { - self.pool = value + self.ip_version = value .try_into() - .map_err(|e| format!("error converting supplied value for pool: {}", e)); + .map_err(|e| format!("error converting supplied value for ip_version: {}", e)); self } pub fn source_ips(mut self, value: T) -> Self @@ -51053,30 +52016,24 @@ pub mod types { } } - impl ::std::convert::TryFrom for super::MulticastGroupCreate { + impl ::std::convert::TryFrom for super::MulticastGroupJoinSpec { type Error = super::error::ConversionError; fn try_from( - value: MulticastGroupCreate, + value: MulticastGroupJoinSpec, ) -> ::std::result::Result { Ok(Self { - description: value.description?, - multicast_ip: value.multicast_ip?, - mvlan: value.mvlan?, - name: value.name?, - pool: value.pool?, + group: value.group?, + ip_version: value.ip_version?, source_ips: value.source_ips?, }) } } - impl ::std::convert::From for MulticastGroupCreate { - fn from(value: super::MulticastGroupCreate) -> Self { + impl ::std::convert::From for MulticastGroupJoinSpec { + fn from(value: super::MulticastGroupJoinSpec) -> Self { Self { - description: Ok(value.description), - multicast_ip: Ok(value.multicast_ip), - mvlan: Ok(value.mvlan), - name: Ok(value.name), - pool: Ok(value.pool), + group: Ok(value.group), + ip_version: Ok(value.ip_version), source_ips: Ok(value.source_ips), } } @@ -51088,7 +52045,10 @@ pub mod types { id: ::std::result::Result<::uuid::Uuid, ::std::string::String>, instance_id: ::std::result::Result<::uuid::Uuid, ::std::string::String>, multicast_group_id: ::std::result::Result<::uuid::Uuid, ::std::string::String>, + multicast_ip: ::std::result::Result<::std::net::IpAddr, ::std::string::String>, name: ::std::result::Result, + source_ips: + ::std::result::Result<::std::vec::Vec<::std::net::IpAddr>, ::std::string::String>, state: ::std::result::Result<::std::string::String, ::std::string::String>, time_created: ::std::result::Result< ::chrono::DateTime<::chrono::offset::Utc>, @@ -51107,7 +52067,9 @@ pub mod types { id: Err("no value supplied for id".to_string()), instance_id: Err("no value supplied for instance_id".to_string()), multicast_group_id: Err("no value supplied for multicast_group_id".to_string()), + multicast_ip: Err("no value supplied for multicast_ip".to_string()), name: Err("no value supplied for name".to_string()), + source_ips: Err("no value supplied for source_ips".to_string()), state: Err("no value supplied for state".to_string()), time_created: Err("no value supplied for time_created".to_string()), time_modified: Err("no value supplied for time_modified".to_string()), @@ -51159,6 +52121,16 @@ pub mod types { }); self } + pub fn multicast_ip(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::net::IpAddr>, + T::Error: ::std::fmt::Display, + { + self.multicast_ip = value.try_into().map_err(|e| { + format!("error converting supplied value for multicast_ip: {}", e) + }); + self + } pub fn name(mut self, value: T) -> Self where T: ::std::convert::TryInto, @@ -51169,6 +52141,16 @@ pub mod types { .map_err(|e| format!("error converting supplied value for name: {}", e)); self } + pub fn source_ips(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec<::std::net::IpAddr>>, + T::Error: ::std::fmt::Display, + { + self.source_ips = value + .try_into() + .map_err(|e| format!("error converting supplied value for source_ips: {}", e)); + self + } pub fn state(mut self, value: T) -> Self where T: ::std::convert::TryInto<::std::string::String>, @@ -51211,7 +52193,9 @@ pub mod types { id: value.id?, instance_id: value.instance_id?, multicast_group_id: value.multicast_group_id?, + multicast_ip: value.multicast_ip?, name: value.name?, + source_ips: value.source_ips?, state: value.state?, time_created: value.time_created?, time_modified: value.time_modified?, @@ -51226,7 +52210,9 @@ pub mod types { id: Ok(value.id), instance_id: Ok(value.instance_id), multicast_group_id: Ok(value.multicast_group_id), + multicast_ip: Ok(value.multicast_ip), name: Ok(value.name), + source_ips: Ok(value.source_ips), state: Ok(value.state), time_created: Ok(value.time_created), time_modified: Ok(value.time_modified), @@ -51234,51 +52220,6 @@ pub mod types { } } - #[derive(Clone, Debug)] - pub struct MulticastGroupMemberAdd { - instance: ::std::result::Result, - } - - impl ::std::default::Default for MulticastGroupMemberAdd { - fn default() -> Self { - Self { - instance: Err("no value supplied for instance".to_string()), - } - } - } - - impl MulticastGroupMemberAdd { - pub fn instance(mut self, value: T) -> Self - where - T: ::std::convert::TryInto, - T::Error: ::std::fmt::Display, - { - self.instance = value - .try_into() - .map_err(|e| format!("error converting supplied value for instance: {}", e)); - self - } - } - - impl ::std::convert::TryFrom for super::MulticastGroupMemberAdd { - type Error = super::error::ConversionError; - fn try_from( - value: MulticastGroupMemberAdd, - ) -> ::std::result::Result { - Ok(Self { - instance: value.instance?, - }) - } - } - - impl ::std::convert::From for MulticastGroupMemberAdd { - fn from(value: super::MulticastGroupMemberAdd) -> Self { - Self { - instance: Ok(value.instance), - } - } - } - #[derive(Clone, Debug)] pub struct MulticastGroupMemberResultsPage { items: ::std::result::Result< @@ -51413,113 +52354,15 @@ pub mod types { } } - #[derive(Clone, Debug)] - pub struct MulticastGroupUpdate { - description: ::std::result::Result< - ::std::option::Option<::std::string::String>, - ::std::string::String, - >, - mvlan: ::std::result::Result<::std::option::Option, ::std::string::String>, - name: ::std::result::Result<::std::option::Option, ::std::string::String>, - source_ips: ::std::result::Result< - ::std::option::Option<::std::vec::Vec<::std::net::IpAddr>>, - ::std::string::String, - >, - } - - impl ::std::default::Default for MulticastGroupUpdate { - fn default() -> Self { - Self { - description: Ok(Default::default()), - mvlan: Ok(Default::default()), - name: Ok(Default::default()), - source_ips: Ok(Default::default()), - } - } - } - - impl MulticastGroupUpdate { - pub fn description(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, - T::Error: ::std::fmt::Display, - { - self.description = value - .try_into() - .map_err(|e| format!("error converting supplied value for description: {}", e)); - self - } - pub fn mvlan(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::option::Option>, - T::Error: ::std::fmt::Display, - { - self.mvlan = value - .try_into() - .map_err(|e| format!("error converting supplied value for mvlan: {}", e)); - self - } - pub fn name(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::option::Option>, - T::Error: ::std::fmt::Display, - { - self.name = value - .try_into() - .map_err(|e| format!("error converting supplied value for name: {}", e)); - self - } - pub fn source_ips(mut self, value: T) -> Self - where - T: ::std::convert::TryInto< - ::std::option::Option<::std::vec::Vec<::std::net::IpAddr>>, - >, - T::Error: ::std::fmt::Display, - { - self.source_ips = value - .try_into() - .map_err(|e| format!("error converting supplied value for source_ips: {}", e)); - self - } - } - - impl ::std::convert::TryFrom for super::MulticastGroupUpdate { - type Error = super::error::ConversionError; - fn try_from( - value: MulticastGroupUpdate, - ) -> ::std::result::Result { - Ok(Self { - description: value.description?, - mvlan: value.mvlan?, - name: value.name?, - source_ips: value.source_ips?, - }) - } - } - - impl ::std::convert::From for MulticastGroupUpdate { - fn from(value: super::MulticastGroupUpdate) -> Self { - Self { - description: Ok(value.description), - mvlan: Ok(value.mvlan), - name: Ok(value.name), - source_ips: Ok(value.source_ips), - } - } - } - #[derive(Clone, Debug)] pub struct NetworkInterface { id: ::std::result::Result<::uuid::Uuid, ::std::string::String>, - ip: ::std::result::Result<::std::net::IpAddr, ::std::string::String>, + ip_config: ::std::result::Result, kind: ::std::result::Result, mac: ::std::result::Result, name: ::std::result::Result, primary: ::std::result::Result, slot: ::std::result::Result, - subnet: ::std::result::Result, - transit_ips: - ::std::result::Result<::std::vec::Vec, ::std::string::String>, vni: ::std::result::Result, } @@ -51527,14 +52370,12 @@ pub mod types { fn default() -> Self { Self { id: Err("no value supplied for id".to_string()), - ip: Err("no value supplied for ip".to_string()), + ip_config: Err("no value supplied for ip_config".to_string()), kind: Err("no value supplied for kind".to_string()), mac: Err("no value supplied for mac".to_string()), name: Err("no value supplied for name".to_string()), primary: Err("no value supplied for primary".to_string()), slot: Err("no value supplied for slot".to_string()), - subnet: Err("no value supplied for subnet".to_string()), - transit_ips: Ok(Default::default()), vni: Err("no value supplied for vni".to_string()), } } @@ -51551,14 +52392,14 @@ pub mod types { .map_err(|e| format!("error converting supplied value for id: {}", e)); self } - pub fn ip(mut self, value: T) -> Self + pub fn ip_config(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::net::IpAddr>, + T: ::std::convert::TryInto, T::Error: ::std::fmt::Display, { - self.ip = value + self.ip_config = value .try_into() - .map_err(|e| format!("error converting supplied value for ip: {}", e)); + .map_err(|e| format!("error converting supplied value for ip_config: {}", e)); self } pub fn kind(mut self, value: T) -> Self @@ -51611,26 +52452,6 @@ pub mod types { .map_err(|e| format!("error converting supplied value for slot: {}", e)); self } - pub fn subnet(mut self, value: T) -> Self - where - T: ::std::convert::TryInto, - T::Error: ::std::fmt::Display, - { - self.subnet = value - .try_into() - .map_err(|e| format!("error converting supplied value for subnet: {}", e)); - self - } - pub fn transit_ips(mut self, value: T) -> Self - where - T: ::std::convert::TryInto<::std::vec::Vec>, - T::Error: ::std::fmt::Display, - { - self.transit_ips = value - .try_into() - .map_err(|e| format!("error converting supplied value for transit_ips: {}", e)); - self - } pub fn vni(mut self, value: T) -> Self where T: ::std::convert::TryInto, @@ -51650,14 +52471,12 @@ pub mod types { ) -> ::std::result::Result { Ok(Self { id: value.id?, - ip: value.ip?, + ip_config: value.ip_config?, kind: value.kind?, mac: value.mac?, name: value.name?, primary: value.primary?, slot: value.slot?, - subnet: value.subnet?, - transit_ips: value.transit_ips?, vni: value.vni?, }) } @@ -51667,14 +52486,12 @@ pub mod types { fn from(value: super::NetworkInterface) -> Self { Self { id: Ok(value.id), - ip: Ok(value.ip), + ip_config: Ok(value.ip_config), kind: Ok(value.kind), mac: Ok(value.mac), name: Ok(value.name), primary: Ok(value.primary), slot: Ok(value.slot), - subnet: Ok(value.subnet), - transit_ips: Ok(value.transit_ips), vni: Ok(value.vni), } } @@ -52154,6 +52971,394 @@ pub mod types { } } + #[derive(Clone, Debug)] + pub struct PrivateIpv4Config { + ip: ::std::result::Result<::std::net::Ipv4Addr, ::std::string::String>, + subnet: ::std::result::Result, + transit_ips: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + } + + impl ::std::default::Default for PrivateIpv4Config { + fn default() -> Self { + Self { + ip: Err("no value supplied for ip".to_string()), + subnet: Err("no value supplied for subnet".to_string()), + transit_ips: Ok(Default::default()), + } + } + } + + impl PrivateIpv4Config { + pub fn ip(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::net::Ipv4Addr>, + T::Error: ::std::fmt::Display, + { + self.ip = value + .try_into() + .map_err(|e| format!("error converting supplied value for ip: {}", e)); + self + } + pub fn subnet(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.subnet = value + .try_into() + .map_err(|e| format!("error converting supplied value for subnet: {}", e)); + self + } + pub fn transit_ips(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.transit_ips = value + .try_into() + .map_err(|e| format!("error converting supplied value for transit_ips: {}", e)); + self + } + } + + impl ::std::convert::TryFrom for super::PrivateIpv4Config { + type Error = super::error::ConversionError; + fn try_from( + value: PrivateIpv4Config, + ) -> ::std::result::Result { + Ok(Self { + ip: value.ip?, + subnet: value.subnet?, + transit_ips: value.transit_ips?, + }) + } + } + + impl ::std::convert::From for PrivateIpv4Config { + fn from(value: super::PrivateIpv4Config) -> Self { + Self { + ip: Ok(value.ip), + subnet: Ok(value.subnet), + transit_ips: Ok(value.transit_ips), + } + } + } + + #[derive(Clone, Debug)] + pub struct PrivateIpv4Stack { + ip: ::std::result::Result<::std::net::Ipv4Addr, ::std::string::String>, + transit_ips: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + } + + impl ::std::default::Default for PrivateIpv4Stack { + fn default() -> Self { + Self { + ip: Err("no value supplied for ip".to_string()), + transit_ips: Err("no value supplied for transit_ips".to_string()), + } + } + } + + impl PrivateIpv4Stack { + pub fn ip(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::net::Ipv4Addr>, + T::Error: ::std::fmt::Display, + { + self.ip = value + .try_into() + .map_err(|e| format!("error converting supplied value for ip: {}", e)); + self + } + pub fn transit_ips(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.transit_ips = value + .try_into() + .map_err(|e| format!("error converting supplied value for transit_ips: {}", e)); + self + } + } + + impl ::std::convert::TryFrom for super::PrivateIpv4Stack { + type Error = super::error::ConversionError; + fn try_from( + value: PrivateIpv4Stack, + ) -> ::std::result::Result { + Ok(Self { + ip: value.ip?, + transit_ips: value.transit_ips?, + }) + } + } + + impl ::std::convert::From for PrivateIpv4Stack { + fn from(value: super::PrivateIpv4Stack) -> Self { + Self { + ip: Ok(value.ip), + transit_ips: Ok(value.transit_ips), + } + } + } + + #[derive(Clone, Debug)] + pub struct PrivateIpv4StackCreate { + ip: ::std::result::Result, + transit_ips: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + } + + impl ::std::default::Default for PrivateIpv4StackCreate { + fn default() -> Self { + Self { + ip: Err("no value supplied for ip".to_string()), + transit_ips: Ok(Default::default()), + } + } + } + + impl PrivateIpv4StackCreate { + pub fn ip(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.ip = value + .try_into() + .map_err(|e| format!("error converting supplied value for ip: {}", e)); + self + } + pub fn transit_ips(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.transit_ips = value + .try_into() + .map_err(|e| format!("error converting supplied value for transit_ips: {}", e)); + self + } + } + + impl ::std::convert::TryFrom for super::PrivateIpv4StackCreate { + type Error = super::error::ConversionError; + fn try_from( + value: PrivateIpv4StackCreate, + ) -> ::std::result::Result { + Ok(Self { + ip: value.ip?, + transit_ips: value.transit_ips?, + }) + } + } + + impl ::std::convert::From for PrivateIpv4StackCreate { + fn from(value: super::PrivateIpv4StackCreate) -> Self { + Self { + ip: Ok(value.ip), + transit_ips: Ok(value.transit_ips), + } + } + } + + #[derive(Clone, Debug)] + pub struct PrivateIpv6Config { + ip: ::std::result::Result<::std::net::Ipv6Addr, ::std::string::String>, + subnet: ::std::result::Result, + transit_ips: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + } + + impl ::std::default::Default for PrivateIpv6Config { + fn default() -> Self { + Self { + ip: Err("no value supplied for ip".to_string()), + subnet: Err("no value supplied for subnet".to_string()), + transit_ips: Err("no value supplied for transit_ips".to_string()), + } + } + } + + impl PrivateIpv6Config { + pub fn ip(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::net::Ipv6Addr>, + T::Error: ::std::fmt::Display, + { + self.ip = value + .try_into() + .map_err(|e| format!("error converting supplied value for ip: {}", e)); + self + } + pub fn subnet(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.subnet = value + .try_into() + .map_err(|e| format!("error converting supplied value for subnet: {}", e)); + self + } + pub fn transit_ips(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.transit_ips = value + .try_into() + .map_err(|e| format!("error converting supplied value for transit_ips: {}", e)); + self + } + } + + impl ::std::convert::TryFrom for super::PrivateIpv6Config { + type Error = super::error::ConversionError; + fn try_from( + value: PrivateIpv6Config, + ) -> ::std::result::Result { + Ok(Self { + ip: value.ip?, + subnet: value.subnet?, + transit_ips: value.transit_ips?, + }) + } + } + + impl ::std::convert::From for PrivateIpv6Config { + fn from(value: super::PrivateIpv6Config) -> Self { + Self { + ip: Ok(value.ip), + subnet: Ok(value.subnet), + transit_ips: Ok(value.transit_ips), + } + } + } + + #[derive(Clone, Debug)] + pub struct PrivateIpv6Stack { + ip: ::std::result::Result<::std::net::Ipv6Addr, ::std::string::String>, + transit_ips: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + } + + impl ::std::default::Default for PrivateIpv6Stack { + fn default() -> Self { + Self { + ip: Err("no value supplied for ip".to_string()), + transit_ips: Err("no value supplied for transit_ips".to_string()), + } + } + } + + impl PrivateIpv6Stack { + pub fn ip(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::net::Ipv6Addr>, + T::Error: ::std::fmt::Display, + { + self.ip = value + .try_into() + .map_err(|e| format!("error converting supplied value for ip: {}", e)); + self + } + pub fn transit_ips(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.transit_ips = value + .try_into() + .map_err(|e| format!("error converting supplied value for transit_ips: {}", e)); + self + } + } + + impl ::std::convert::TryFrom for super::PrivateIpv6Stack { + type Error = super::error::ConversionError; + fn try_from( + value: PrivateIpv6Stack, + ) -> ::std::result::Result { + Ok(Self { + ip: value.ip?, + transit_ips: value.transit_ips?, + }) + } + } + + impl ::std::convert::From for PrivateIpv6Stack { + fn from(value: super::PrivateIpv6Stack) -> Self { + Self { + ip: Ok(value.ip), + transit_ips: Ok(value.transit_ips), + } + } + } + + #[derive(Clone, Debug)] + pub struct PrivateIpv6StackCreate { + ip: ::std::result::Result, + transit_ips: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + } + + impl ::std::default::Default for PrivateIpv6StackCreate { + fn default() -> Self { + Self { + ip: Err("no value supplied for ip".to_string()), + transit_ips: Ok(Default::default()), + } + } + } + + impl PrivateIpv6StackCreate { + pub fn ip(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.ip = value + .try_into() + .map_err(|e| format!("error converting supplied value for ip: {}", e)); + self + } + pub fn transit_ips(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.transit_ips = value + .try_into() + .map_err(|e| format!("error converting supplied value for transit_ips: {}", e)); + self + } + } + + impl ::std::convert::TryFrom for super::PrivateIpv6StackCreate { + type Error = super::error::ConversionError; + fn try_from( + value: PrivateIpv6StackCreate, + ) -> ::std::result::Result { + Ok(Self { + ip: value.ip?, + transit_ips: value.transit_ips?, + }) + } + } + + impl ::std::convert::From for PrivateIpv6StackCreate { + fn from(value: super::PrivateIpv6StackCreate) -> Self { + Self { + ip: Ok(value.ip), + transit_ips: Ok(value.transit_ips), + } + } + } + #[derive(Clone, Debug)] pub struct Probe { description: ::std::result::Result<::std::string::String, ::std::string::String>, @@ -52278,11 +53483,8 @@ pub mod types { #[derive(Clone, Debug)] pub struct ProbeCreate { description: ::std::result::Result<::std::string::String, ::std::string::String>, - ip_pool: ::std::result::Result< - ::std::option::Option, - ::std::string::String, - >, name: ::std::result::Result, + pool_selector: ::std::result::Result, sled: ::std::result::Result<::uuid::Uuid, ::std::string::String>, } @@ -52290,8 +53492,8 @@ pub mod types { fn default() -> Self { Self { description: Err("no value supplied for description".to_string()), - ip_pool: Ok(Default::default()), name: Err("no value supplied for name".to_string()), + pool_selector: Ok(super::defaults::probe_create_pool_selector()), sled: Err("no value supplied for sled".to_string()), } } @@ -52308,24 +53510,24 @@ pub mod types { .map_err(|e| format!("error converting supplied value for description: {}", e)); self } - pub fn ip_pool(mut self, value: T) -> Self + pub fn name(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::option::Option>, + T: ::std::convert::TryInto, T::Error: ::std::fmt::Display, { - self.ip_pool = value + self.name = value .try_into() - .map_err(|e| format!("error converting supplied value for ip_pool: {}", e)); + .map_err(|e| format!("error converting supplied value for name: {}", e)); self } - pub fn name(mut self, value: T) -> Self + pub fn pool_selector(mut self, value: T) -> Self where - T: ::std::convert::TryInto, + T: ::std::convert::TryInto, T::Error: ::std::fmt::Display, { - self.name = value - .try_into() - .map_err(|e| format!("error converting supplied value for name: {}", e)); + self.pool_selector = value.try_into().map_err(|e| { + format!("error converting supplied value for pool_selector: {}", e) + }); self } pub fn sled(mut self, value: T) -> Self @@ -52347,8 +53549,8 @@ pub mod types { ) -> ::std::result::Result { Ok(Self { description: value.description?, - ip_pool: value.ip_pool?, name: value.name?, + pool_selector: value.pool_selector?, sled: value.sled?, }) } @@ -52358,8 +53560,8 @@ pub mod types { fn from(value: super::ProbeCreate) -> Self { Self { description: Ok(value.description), - ip_pool: Ok(value.ip_pool), name: Ok(value.name), + pool_selector: Ok(value.pool_selector), sled: Ok(value.sled), } } @@ -63437,9 +64639,48 @@ pub mod types { V } + pub(super) fn address_selector_auto_pool_selector() -> super::PoolSelector { + super::PoolSelector::Auto { + ip_version: ::std::option::Option::None, + } + } + + pub(super) fn ephemeral_ip_create_pool_selector() -> super::PoolSelector { + super::PoolSelector::Auto { + ip_version: ::std::option::Option::None, + } + } + + pub(super) fn external_ip_create_ephemeral_pool_selector() -> super::PoolSelector { + super::PoolSelector::Auto { + ip_version: ::std::option::Option::None, + } + } + + pub(super) fn floating_ip_create_address_selector() -> super::AddressSelector { + super::AddressSelector::Auto { + pool_selector: super::PoolSelector::Auto { + ip_version: ::std::option::Option::None, + }, + } + } + pub(super) fn instance_create_network_interfaces( ) -> super::InstanceNetworkInterfaceAttachment { - super::InstanceNetworkInterfaceAttachment::Default + super::InstanceNetworkInterfaceAttachment::DefaultDualStack + } + + pub(super) fn instance_network_interface_create_ip_config() -> super::PrivateIpStackCreate { + super::PrivateIpStackCreate::DualStack { + v4: super::PrivateIpv4StackCreate { + ip: super::Ipv4Assignment::Auto, + transit_ips: vec![], + }, + v6: super::PrivateIpv6StackCreate { + ip: super::Ipv6Assignment::Auto, + transit_ips: vec![], + }, + } } pub(super) fn ip_pool_create_ip_version() -> super::IpVersion { @@ -63449,6 +64690,12 @@ pub mod types { pub(super) fn ip_pool_create_pool_type() -> super::IpPoolType { super::IpPoolType::Unicast } + + pub(super) fn probe_create_pool_selector() -> super::PoolSelector { + super::PoolSelector::Auto { + ip_version: ::std::option::Option::None, + } + } } } @@ -63457,7 +64704,7 @@ pub mod types { /// /// API for interacting with the Oxide control plane /// -/// Version: 2026010100.0.0 +/// Version: 2026010800.0.0 pub struct Client { pub(crate) baseurl: String, pub(crate) client: reqwest::Client, @@ -63498,7 +64745,7 @@ impl Client { impl ClientInfo<()> for Client { fn api_version() -> &'static str { - "2026010100.0.0" + "2026010800.0.0" } fn baseurl(&self) -> &str { @@ -64537,57 +65784,92 @@ pub trait ClientExperimentalExt { /// .await; /// ``` fn instance_affinity_group_list(&self) -> builder::InstanceAffinityGroupList<'_>; - /// List multicast groups for instance + /// List multicast groups for an instance /// /// Sends a `GET` request to `/v1/instances/{instance}/multicast-groups` /// /// Arguments: /// - `instance`: Name or ID of the instance + /// - `limit`: Maximum number of items returned by a single call + /// - `page_token`: Token returned by previous call to retrieve the + /// subsequent page /// - `project`: Name or ID of the project + /// - `sort_by` /// ```ignore /// let response = client.instance_multicast_group_list() /// .instance(instance) + /// .limit(limit) + /// .page_token(page_token) /// .project(project) + /// .sort_by(sort_by) /// .send() /// .await; /// ``` fn instance_multicast_group_list(&self) -> builder::InstanceMulticastGroupList<'_>; - /// Join multicast group + /// Join a multicast group /// /// This is functionally equivalent to adding the instance via the group's /// member management endpoint or updating the instance's `multicast_groups` /// field. All approaches modify the same membership and trigger /// reconciliation. /// + /// Authorization: requires Modify on the instance identified in the URL + /// path (checked first) and Read on the multicast group. Checking instance + /// permission first prevents creating orphaned groups when the instance + /// check fails. + /// + /// Group Identification: Groups can be referenced by name, IP address, or + /// UUID. All three are fleet-wide unique identifiers: - By name: If group + /// doesn't exist, it's implicitly created with an auto-allocated IP from a + /// multicast pool linked to the caller's silo. Pool selection prefers the + /// default pool; if none, selects alphabetically. - By IP: If group doesn't + /// exist, it's implicitly created using that IP. The pool is determined by + /// which pool contains the IP. - By UUID: Group must already exist. + /// + /// Source IP filtering: - Duplicate IPs in the request are automatically + /// deduplicated. - Maximum of 64 source IPs allowed (per RFC 3376, IGMPv3). + /// - ASM: Sources are optional. Providing sources enables source filtering + /// via IGMPv3/MLDv2 even for ASM addresses. - SSM: Sources are required. + /// SSM addresses (232.0.0.0/8 for IPv4, ff3x::/32 for IPv6) must have at + /// least one source specified. + /// /// Sends a `PUT` request to /// `/v1/instances/{instance}/multicast-groups/{multicast_group}` /// /// Arguments: /// - `instance`: Name or ID of the instance - /// - `multicast_group`: Name or ID of the multicast group + /// - `multicast_group`: Name, ID, or IP address of the multicast group /// - `project`: Name or ID of the project + /// - `body` /// ```ignore /// let response = client.instance_multicast_group_join() /// .instance(instance) /// .multicast_group(multicast_group) /// .project(project) + /// .body(body) /// .send() /// .await; /// ``` fn instance_multicast_group_join(&self) -> builder::InstanceMulticastGroupJoin<'_>; - /// Leave multicast group + /// Leave a multicast group + /// + /// The group can be specified by name, UUID, or multicast IP address. All + /// three are fleet-wide unique identifiers. /// /// This is functionally equivalent to removing the instance via the group's /// member management endpoint or updating the instance's `multicast_groups` /// field. All approaches modify the same membership and trigger /// reconciliation. /// + /// Authorization: requires Modify on the instance (checked first) and Read + /// on the multicast group. + /// /// Sends a `DELETE` request to /// `/v1/instances/{instance}/multicast-groups/{multicast_group}` /// /// Arguments: /// - `instance`: Name or ID of the instance - /// - `multicast_group`: Name or ID of the multicast group + /// - `multicast_group`: Name, ID, or IP address of the multicast group /// - `project`: Name or ID of the project /// ```ignore /// let response = client.instance_multicast_group_leave() @@ -64598,7 +65880,7 @@ pub trait ClientExperimentalExt { /// .await; /// ``` fn instance_multicast_group_leave(&self) -> builder::InstanceMulticastGroupLeave<'_>; - /// List all multicast groups + /// List multicast groups /// /// Sends a `GET` request to `/v1/multicast-groups` /// @@ -64616,27 +65898,15 @@ pub trait ClientExperimentalExt { /// .await; /// ``` fn multicast_group_list(&self) -> builder::MulticastGroupList<'_>; - /// Create a multicast group - /// - /// Multicast groups are fleet-scoped resources that can be joined by - /// instances across projects and silos. A single multicast IP serves all - /// group members regardless of project or silo boundaries. - /// - /// Sends a `POST` request to `/v1/multicast-groups` - /// - /// ```ignore - /// let response = client.multicast_group_create() - /// .body(body) - /// .send() - /// .await; - /// ``` - fn multicast_group_create(&self) -> builder::MulticastGroupCreate<'_>; /// Fetch a multicast group /// + /// The group can be specified by name, UUID, or multicast IP address. + /// (e.g., "224.1.2.3" or "ff38::1"). + /// /// Sends a `GET` request to `/v1/multicast-groups/{multicast_group}` /// /// Arguments: - /// - `multicast_group`: Name or ID of the multicast group + /// - `multicast_group`: Name, ID, or IP address of the multicast group /// ```ignore /// let response = client.multicast_group_view() /// .multicast_group(multicast_group) @@ -64644,41 +65914,15 @@ pub trait ClientExperimentalExt { /// .await; /// ``` fn multicast_group_view(&self) -> builder::MulticastGroupView<'_>; - /// Update a multicast group - /// - /// Sends a `PUT` request to `/v1/multicast-groups/{multicast_group}` - /// - /// Arguments: - /// - `multicast_group`: Name or ID of the multicast group - /// - `body` - /// ```ignore - /// let response = client.multicast_group_update() - /// .multicast_group(multicast_group) - /// .body(body) - /// .send() - /// .await; - /// ``` - fn multicast_group_update(&self) -> builder::MulticastGroupUpdate<'_>; - /// Delete a multicast group - /// - /// Sends a `DELETE` request to `/v1/multicast-groups/{multicast_group}` - /// - /// Arguments: - /// - `multicast_group`: Name or ID of the multicast group - /// ```ignore - /// let response = client.multicast_group_delete() - /// .multicast_group(multicast_group) - /// .send() - /// .await; - /// ``` - fn multicast_group_delete(&self) -> builder::MulticastGroupDelete<'_>; /// List members of a multicast group /// + /// The group can be specified by name, UUID, or multicast IP address. + /// /// Sends a `GET` request to /// `/v1/multicast-groups/{multicast_group}/members` /// /// Arguments: - /// - `multicast_group`: Name or ID of the multicast group + /// - `multicast_group`: Name, ID, or IP address of the multicast group /// - `limit`: Maximum number of items returned by a single call /// - `page_token`: Token returned by previous call to retrieve the /// subsequent page @@ -64693,67 +65937,6 @@ pub trait ClientExperimentalExt { /// .await; /// ``` fn multicast_group_member_list(&self) -> builder::MulticastGroupMemberList<'_>; - /// Add instance to a multicast group - /// - /// Functionally equivalent to updating the instance's `multicast_groups` - /// field. Both approaches modify the same underlying membership and trigger - /// the same reconciliation logic. - /// - /// Specify instance by name (requires `?project=`) or UUID. - /// - /// Sends a `POST` request to - /// `/v1/multicast-groups/{multicast_group}/members` - /// - /// Arguments: - /// - `multicast_group`: Name or ID of the multicast group - /// - `project`: Name or ID of the project - /// - `body` - /// ```ignore - /// let response = client.multicast_group_member_add() - /// .multicast_group(multicast_group) - /// .project(project) - /// .body(body) - /// .send() - /// .await; - /// ``` - fn multicast_group_member_add(&self) -> builder::MulticastGroupMemberAdd<'_>; - /// Remove instance from a multicast group - /// - /// Functionally equivalent to removing the group from the instance's - /// `multicast_groups` field. Both approaches modify the same underlying - /// membership and trigger reconciliation. - /// - /// Specify instance by name (requires `?project=`) or UUID. - /// - /// Sends a `DELETE` request to - /// `/v1/multicast-groups/{multicast_group}/members/{instance}` - /// - /// Arguments: - /// - `multicast_group`: Name or ID of the multicast group - /// - `instance`: Name or ID of the instance - /// - `project`: Name or ID of the project - /// ```ignore - /// let response = client.multicast_group_member_remove() - /// .multicast_group(multicast_group) - /// .instance(instance) - /// .project(project) - /// .send() - /// .await; - /// ``` - fn multicast_group_member_remove(&self) -> builder::MulticastGroupMemberRemove<'_>; - /// Look up multicast group by IP address - /// - /// Sends a `GET` request to `/v1/system/multicast-groups/by-ip/{address}` - /// - /// Arguments: - /// - `address`: IP address of the multicast group - /// ```ignore - /// let response = client.lookup_multicast_group_by_ip() - /// .address(address) - /// .send() - /// .await; - /// ``` - fn lookup_multicast_group_by_ip(&self) -> builder::LookupMulticastGroupByIp<'_>; /// Run project-scoped timeseries query /// /// Queries are written in OxQL. Project must be specified by name or ID in @@ -64890,38 +66073,14 @@ impl ClientExperimentalExt for Client { builder::MulticastGroupList::new(self) } - fn multicast_group_create(&self) -> builder::MulticastGroupCreate<'_> { - builder::MulticastGroupCreate::new(self) - } - fn multicast_group_view(&self) -> builder::MulticastGroupView<'_> { builder::MulticastGroupView::new(self) } - fn multicast_group_update(&self) -> builder::MulticastGroupUpdate<'_> { - builder::MulticastGroupUpdate::new(self) - } - - fn multicast_group_delete(&self) -> builder::MulticastGroupDelete<'_> { - builder::MulticastGroupDelete::new(self) - } - fn multicast_group_member_list(&self) -> builder::MulticastGroupMemberList<'_> { builder::MulticastGroupMemberList::new(self) } - fn multicast_group_member_add(&self) -> builder::MulticastGroupMemberAdd<'_> { - builder::MulticastGroupMemberAdd::new(self) - } - - fn multicast_group_member_remove(&self) -> builder::MulticastGroupMemberRemove<'_> { - builder::MulticastGroupMemberRemove::new(self) - } - - fn lookup_multicast_group_by_ip(&self) -> builder::LookupMulticastGroupByIp<'_> { - builder::LookupMulticastGroupByIp::new(self) - } - fn timeseries_query(&self) -> builder::TimeseriesQuery<'_> { builder::TimeseriesQuery::new(self) } @@ -79531,7 +80690,10 @@ pub mod builder { pub struct InstanceMulticastGroupList<'a> { client: &'a super::Client, instance: Result, + limit: Result, String>, + page_token: Result, String>, project: Result, String>, + sort_by: Result, String>, } impl<'a> InstanceMulticastGroupList<'a> { @@ -79539,7 +80701,10 @@ pub mod builder { Self { client: client, instance: Err("instance was not initialized".to_string()), + limit: Ok(None), + page_token: Ok(None), project: Ok(None), + sort_by: Ok(None), } } @@ -79553,6 +80718,26 @@ pub mod builder { self } + pub fn limit(mut self, value: V) -> Self + where + V: std::convert::TryInto<::std::num::NonZeroU32>, + { + self.limit = value.try_into().map(Some).map_err(|_| { + "conversion to `:: std :: num :: NonZeroU32` for limit failed".to_string() + }); + self + } + + pub fn page_token(mut self, value: V) -> Self + where + V: std::convert::TryInto<::std::string::String>, + { + self.page_token = value.try_into().map(Some).map_err(|_| { + "conversion to `:: std :: string :: String` for page_token failed".to_string() + }); + self + } + pub fn project(mut self, value: V) -> Self where V: std::convert::TryInto, @@ -79564,6 +80749,17 @@ pub mod builder { self } + pub fn sort_by(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.sort_by = value + .try_into() + .map(Some) + .map_err(|_| "conversion to `IdSortMode` for sort_by failed".to_string()); + self + } + /// Sends a `GET` request to `/v1/instances/{instance}/multicast-groups` pub async fn send( self, @@ -79572,10 +80768,16 @@ pub mod builder { let Self { client, instance, + limit, + page_token, project, + sort_by, } = self; let instance = instance.map_err(Error::InvalidRequest)?; + let limit = limit.map_err(Error::InvalidRequest)?; + let page_token = page_token.map_err(Error::InvalidRequest)?; let project = project.map_err(Error::InvalidRequest)?; + let sort_by = sort_by.map_err(Error::InvalidRequest)?; let url = format!( "{}/v1/instances/{}/multicast-groups", client.baseurl, @@ -79594,7 +80796,13 @@ pub mod builder { ::reqwest::header::ACCEPT, ::reqwest::header::HeaderValue::from_static("application/json"), ) + .query(&progenitor_client::QueryParam::new("limit", &limit)) + .query(&progenitor_client::QueryParam::new( + "page_token", + &page_token, + )) .query(&progenitor_client::QueryParam::new("project", &project)) + .query(&progenitor_client::QueryParam::new("sort_by", &sort_by)) .headers(header_map) .build()?; let info = OperationInfo { @@ -79615,6 +80823,55 @@ pub mod builder { _ => Err(Error::UnexpectedResponse(response)), } } + + /// Streams `GET` requests to + /// `/v1/instances/{instance}/multicast-groups` + pub fn stream( + self, + ) -> impl futures::Stream>> + + Unpin + + 'a { + use ::futures::StreamExt; + use ::futures::TryFutureExt; + use ::futures::TryStreamExt; + let next = Self { + page_token: Ok(None), + project: Ok(None), + sort_by: Ok(None), + ..self.clone() + }; + self.send() + .map_ok(move |page| { + let page = page.into_inner(); + let first = futures::stream::iter(page.items).map(Ok); + let rest = futures::stream::try_unfold( + (page.next_page, next), + |(next_page, next)| async { + if next_page.is_none() { + Ok(None) + } else { + Self { + page_token: Ok(next_page), + ..next.clone() + } + .send() + .map_ok(|page| { + let page = page.into_inner(); + Some(( + futures::stream::iter(page.items).map(Ok), + (page.next_page, next), + )) + }) + .await + } + }, + ) + .try_flatten(); + first.chain(rest) + }) + .try_flatten_stream() + .boxed() + } } /// Builder for [`ClientExperimentalExt::instance_multicast_group_join`] @@ -79624,8 +80881,9 @@ pub mod builder { pub struct InstanceMulticastGroupJoin<'a> { client: &'a super::Client, instance: Result, - multicast_group: Result, + multicast_group: Result, project: Result, String>, + body: Result, } impl<'a> InstanceMulticastGroupJoin<'a> { @@ -79635,6 +80893,7 @@ pub mod builder { instance: Err("instance was not initialized".to_string()), multicast_group: Err("multicast_group was not initialized".to_string()), project: Ok(None), + body: Ok(::std::default::Default::default()), } } @@ -79650,11 +80909,11 @@ pub mod builder { pub fn multicast_group(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.multicast_group = value - .try_into() - .map_err(|_| "conversion to `NameOrId` for multicast_group failed".to_string()); + self.multicast_group = value.try_into().map_err(|_| { + "conversion to `MulticastGroupIdentifier` for multicast_group failed".to_string() + }); self } @@ -79669,6 +80928,31 @@ pub mod builder { self } + pub fn body(mut self, value: V) -> Self + where + V: std::convert::TryInto, + >::Error: + std::fmt::Display, + { + self.body = value.try_into().map(From::from).map_err(|s| { + format!( + "conversion to `InstanceMulticastGroupJoin` for body failed: {}", + s + ) + }); + self + } + + pub fn body_map(mut self, f: F) -> Self + where + F: std::ops::FnOnce( + types::builder::InstanceMulticastGroupJoin, + ) -> types::builder::InstanceMulticastGroupJoin, + { + self.body = self.body.map(f); + self + } + /// Sends a `PUT` request to /// `/v1/instances/{instance}/multicast-groups/{multicast_group}` pub async fn send( @@ -79679,10 +80963,16 @@ pub mod builder { instance, multicast_group, project, + body, } = self; let instance = instance.map_err(Error::InvalidRequest)?; let multicast_group = multicast_group.map_err(Error::InvalidRequest)?; let project = project.map_err(Error::InvalidRequest)?; + let body = body + .and_then(|v| { + types::InstanceMulticastGroupJoin::try_from(v).map_err(|e| e.to_string()) + }) + .map_err(Error::InvalidRequest)?; let url = format!( "{}/v1/instances/{}/multicast-groups/{}", client.baseurl, @@ -79702,6 +80992,7 @@ pub mod builder { ::reqwest::header::ACCEPT, ::reqwest::header::HeaderValue::from_static("application/json"), ) + .json(&body) .query(&progenitor_client::QueryParam::new("project", &project)) .headers(header_map) .build()?; @@ -79732,7 +81023,7 @@ pub mod builder { pub struct InstanceMulticastGroupLeave<'a> { client: &'a super::Client, instance: Result, - multicast_group: Result, + multicast_group: Result, project: Result, String>, } @@ -79758,11 +81049,11 @@ pub mod builder { pub fn multicast_group(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.multicast_group = value - .try_into() - .map_err(|_| "conversion to `NameOrId` for multicast_group failed".to_string()); + self.multicast_group = value.try_into().map_err(|_| { + "conversion to `MulticastGroupIdentifier` for multicast_group failed".to_string() + }); self } @@ -83557,523 +84848,7 @@ pub mod builder { .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "multicast_group_list", - }; - client.pre(&mut request, &info).await?; - let result = client.exec(request, &info).await; - client.post(&result, &info).await?; - let response = result?; - match response.status().as_u16() { - 200u16 => ResponseValue::from_response(response).await, - 400u16..=499u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - 500u16..=599u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - _ => Err(Error::UnexpectedResponse(response)), - } - } - - /// Streams `GET` requests to `/v1/multicast-groups` - pub fn stream( - self, - ) -> impl futures::Stream>> + Unpin + 'a - { - use ::futures::StreamExt; - use ::futures::TryFutureExt; - use ::futures::TryStreamExt; - let next = Self { - page_token: Ok(None), - sort_by: Ok(None), - ..self.clone() - }; - self.send() - .map_ok(move |page| { - let page = page.into_inner(); - let first = futures::stream::iter(page.items).map(Ok); - let rest = futures::stream::try_unfold( - (page.next_page, next), - |(next_page, next)| async { - if next_page.is_none() { - Ok(None) - } else { - Self { - page_token: Ok(next_page), - ..next.clone() - } - .send() - .map_ok(|page| { - let page = page.into_inner(); - Some(( - futures::stream::iter(page.items).map(Ok), - (page.next_page, next), - )) - }) - .await - } - }, - ) - .try_flatten(); - first.chain(rest) - }) - .try_flatten_stream() - .boxed() - } - } - - /// Builder for [`ClientExperimentalExt::multicast_group_create`] - /// - /// [`ClientExperimentalExt::multicast_group_create`]: super::ClientExperimentalExt::multicast_group_create - #[derive(Debug, Clone)] - pub struct MulticastGroupCreate<'a> { - client: &'a super::Client, - body: Result, - } - - impl<'a> MulticastGroupCreate<'a> { - pub fn new(client: &'a super::Client) -> Self { - Self { - client: client, - body: Ok(::std::default::Default::default()), - } - } - - pub fn body(mut self, value: V) -> Self - where - V: std::convert::TryInto, - >::Error: std::fmt::Display, - { - self.body = value.try_into().map(From::from).map_err(|s| { - format!( - "conversion to `MulticastGroupCreate` for body failed: {}", - s - ) - }); - self - } - - pub fn body_map(mut self, f: F) -> Self - where - F: std::ops::FnOnce( - types::builder::MulticastGroupCreate, - ) -> types::builder::MulticastGroupCreate, - { - self.body = self.body.map(f); - self - } - - /// Sends a `POST` request to `/v1/multicast-groups` - pub async fn send( - self, - ) -> Result, Error> { - let Self { client, body } = self; - let body = body - .and_then(|v| types::MulticastGroupCreate::try_from(v).map_err(|e| e.to_string())) - .map_err(Error::InvalidRequest)?; - let url = format!("{}/v1/multicast-groups", client.baseurl,); - let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); - header_map.append( - ::reqwest::header::HeaderName::from_static("api-version"), - ::reqwest::header::HeaderValue::from_static(super::Client::api_version()), - ); - #[allow(unused_mut)] - let mut request = client - .client - .post(url) - .header( - ::reqwest::header::ACCEPT, - ::reqwest::header::HeaderValue::from_static("application/json"), - ) - .json(&body) - .headers(header_map) - .build()?; - let info = OperationInfo { - operation_id: "multicast_group_create", - }; - client.pre(&mut request, &info).await?; - let result = client.exec(request, &info).await; - client.post(&result, &info).await?; - let response = result?; - match response.status().as_u16() { - 201u16 => ResponseValue::from_response(response).await, - 400u16..=499u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - 500u16..=599u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - _ => Err(Error::UnexpectedResponse(response)), - } - } - } - - /// Builder for [`ClientExperimentalExt::multicast_group_view`] - /// - /// [`ClientExperimentalExt::multicast_group_view`]: super::ClientExperimentalExt::multicast_group_view - #[derive(Debug, Clone)] - pub struct MulticastGroupView<'a> { - client: &'a super::Client, - multicast_group: Result, - } - - impl<'a> MulticastGroupView<'a> { - pub fn new(client: &'a super::Client) -> Self { - Self { - client: client, - multicast_group: Err("multicast_group was not initialized".to_string()), - } - } - - pub fn multicast_group(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.multicast_group = value - .try_into() - .map_err(|_| "conversion to `NameOrId` for multicast_group failed".to_string()); - self - } - - /// Sends a `GET` request to `/v1/multicast-groups/{multicast_group}` - pub async fn send( - self, - ) -> Result, Error> { - let Self { - client, - multicast_group, - } = self; - let multicast_group = multicast_group.map_err(Error::InvalidRequest)?; - let url = format!( - "{}/v1/multicast-groups/{}", - client.baseurl, - encode_path(&multicast_group.to_string()), - ); - let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); - header_map.append( - ::reqwest::header::HeaderName::from_static("api-version"), - ::reqwest::header::HeaderValue::from_static(super::Client::api_version()), - ); - #[allow(unused_mut)] - let mut request = client - .client - .get(url) - .header( - ::reqwest::header::ACCEPT, - ::reqwest::header::HeaderValue::from_static("application/json"), - ) - .headers(header_map) - .build()?; - let info = OperationInfo { - operation_id: "multicast_group_view", - }; - client.pre(&mut request, &info).await?; - let result = client.exec(request, &info).await; - client.post(&result, &info).await?; - let response = result?; - match response.status().as_u16() { - 200u16 => ResponseValue::from_response(response).await, - 400u16..=499u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - 500u16..=599u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - _ => Err(Error::UnexpectedResponse(response)), - } - } - } - - /// Builder for [`ClientExperimentalExt::multicast_group_update`] - /// - /// [`ClientExperimentalExt::multicast_group_update`]: super::ClientExperimentalExt::multicast_group_update - #[derive(Debug, Clone)] - pub struct MulticastGroupUpdate<'a> { - client: &'a super::Client, - multicast_group: Result, - body: Result, - } - - impl<'a> MulticastGroupUpdate<'a> { - pub fn new(client: &'a super::Client) -> Self { - Self { - client: client, - multicast_group: Err("multicast_group was not initialized".to_string()), - body: Ok(::std::default::Default::default()), - } - } - - pub fn multicast_group(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.multicast_group = value - .try_into() - .map_err(|_| "conversion to `NameOrId` for multicast_group failed".to_string()); - self - } - - pub fn body(mut self, value: V) -> Self - where - V: std::convert::TryInto, - >::Error: std::fmt::Display, - { - self.body = value.try_into().map(From::from).map_err(|s| { - format!( - "conversion to `MulticastGroupUpdate` for body failed: {}", - s - ) - }); - self - } - - pub fn body_map(mut self, f: F) -> Self - where - F: std::ops::FnOnce( - types::builder::MulticastGroupUpdate, - ) -> types::builder::MulticastGroupUpdate, - { - self.body = self.body.map(f); - self - } - - /// Sends a `PUT` request to `/v1/multicast-groups/{multicast_group}` - pub async fn send( - self, - ) -> Result, Error> { - let Self { - client, - multicast_group, - body, - } = self; - let multicast_group = multicast_group.map_err(Error::InvalidRequest)?; - let body = body - .and_then(|v| types::MulticastGroupUpdate::try_from(v).map_err(|e| e.to_string())) - .map_err(Error::InvalidRequest)?; - let url = format!( - "{}/v1/multicast-groups/{}", - client.baseurl, - encode_path(&multicast_group.to_string()), - ); - let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); - header_map.append( - ::reqwest::header::HeaderName::from_static("api-version"), - ::reqwest::header::HeaderValue::from_static(super::Client::api_version()), - ); - #[allow(unused_mut)] - let mut request = client - .client - .put(url) - .header( - ::reqwest::header::ACCEPT, - ::reqwest::header::HeaderValue::from_static("application/json"), - ) - .json(&body) - .headers(header_map) - .build()?; - let info = OperationInfo { - operation_id: "multicast_group_update", - }; - client.pre(&mut request, &info).await?; - let result = client.exec(request, &info).await; - client.post(&result, &info).await?; - let response = result?; - match response.status().as_u16() { - 200u16 => ResponseValue::from_response(response).await, - 400u16..=499u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - 500u16..=599u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - _ => Err(Error::UnexpectedResponse(response)), - } - } - } - - /// Builder for [`ClientExperimentalExt::multicast_group_delete`] - /// - /// [`ClientExperimentalExt::multicast_group_delete`]: super::ClientExperimentalExt::multicast_group_delete - #[derive(Debug, Clone)] - pub struct MulticastGroupDelete<'a> { - client: &'a super::Client, - multicast_group: Result, - } - - impl<'a> MulticastGroupDelete<'a> { - pub fn new(client: &'a super::Client) -> Self { - Self { - client: client, - multicast_group: Err("multicast_group was not initialized".to_string()), - } - } - - pub fn multicast_group(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.multicast_group = value - .try_into() - .map_err(|_| "conversion to `NameOrId` for multicast_group failed".to_string()); - self - } - - /// Sends a `DELETE` request to `/v1/multicast-groups/{multicast_group}` - pub async fn send(self) -> Result, Error> { - let Self { - client, - multicast_group, - } = self; - let multicast_group = multicast_group.map_err(Error::InvalidRequest)?; - let url = format!( - "{}/v1/multicast-groups/{}", - client.baseurl, - encode_path(&multicast_group.to_string()), - ); - let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); - header_map.append( - ::reqwest::header::HeaderName::from_static("api-version"), - ::reqwest::header::HeaderValue::from_static(super::Client::api_version()), - ); - #[allow(unused_mut)] - let mut request = client - .client - .delete(url) - .header( - ::reqwest::header::ACCEPT, - ::reqwest::header::HeaderValue::from_static("application/json"), - ) - .headers(header_map) - .build()?; - let info = OperationInfo { - operation_id: "multicast_group_delete", - }; - client.pre(&mut request, &info).await?; - let result = client.exec(request, &info).await; - client.post(&result, &info).await?; - let response = result?; - match response.status().as_u16() { - 204u16 => Ok(ResponseValue::empty(response)), - 400u16..=499u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - 500u16..=599u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - _ => Err(Error::UnexpectedResponse(response)), - } - } - } - - /// Builder for [`ClientExperimentalExt::multicast_group_member_list`] - /// - /// [`ClientExperimentalExt::multicast_group_member_list`]: super::ClientExperimentalExt::multicast_group_member_list - #[derive(Debug, Clone)] - pub struct MulticastGroupMemberList<'a> { - client: &'a super::Client, - multicast_group: Result, - limit: Result, String>, - page_token: Result, String>, - sort_by: Result, String>, - } - - impl<'a> MulticastGroupMemberList<'a> { - pub fn new(client: &'a super::Client) -> Self { - Self { - client: client, - multicast_group: Err("multicast_group was not initialized".to_string()), - limit: Ok(None), - page_token: Ok(None), - sort_by: Ok(None), - } - } - - pub fn multicast_group(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.multicast_group = value - .try_into() - .map_err(|_| "conversion to `NameOrId` for multicast_group failed".to_string()); - self - } - - pub fn limit(mut self, value: V) -> Self - where - V: std::convert::TryInto<::std::num::NonZeroU32>, - { - self.limit = value.try_into().map(Some).map_err(|_| { - "conversion to `:: std :: num :: NonZeroU32` for limit failed".to_string() - }); - self - } - - pub fn page_token(mut self, value: V) -> Self - where - V: std::convert::TryInto<::std::string::String>, - { - self.page_token = value.try_into().map(Some).map_err(|_| { - "conversion to `:: std :: string :: String` for page_token failed".to_string() - }); - self - } - - pub fn sort_by(mut self, value: V) -> Self - where - V: std::convert::TryInto, - { - self.sort_by = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `IdSortMode` for sort_by failed".to_string()); - self - } - - /// Sends a `GET` request to - /// `/v1/multicast-groups/{multicast_group}/members` - pub async fn send( - self, - ) -> Result, Error> - { - let Self { - client, - multicast_group, - limit, - page_token, - sort_by, - } = self; - let multicast_group = multicast_group.map_err(Error::InvalidRequest)?; - let limit = limit.map_err(Error::InvalidRequest)?; - let page_token = page_token.map_err(Error::InvalidRequest)?; - let sort_by = sort_by.map_err(Error::InvalidRequest)?; - let url = format!( - "{}/v1/multicast-groups/{}/members", - client.baseurl, - encode_path(&multicast_group.to_string()), - ); - let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); - header_map.append( - ::reqwest::header::HeaderName::from_static("api-version"), - ::reqwest::header::HeaderValue::from_static(super::Client::api_version()), - ); - #[allow(unused_mut)] - let mut request = client - .client - .get(url) - .header( - ::reqwest::header::ACCEPT, - ::reqwest::header::HeaderValue::from_static("application/json"), - ) - .query(&progenitor_client::QueryParam::new("limit", &limit)) - .query(&progenitor_client::QueryParam::new( - "page_token", - &page_token, - )) - .query(&progenitor_client::QueryParam::new("sort_by", &sort_by)) - .headers(header_map) - .build()?; - let info = OperationInfo { - operation_id: "multicast_group_member_list", + operation_id: "multicast_group_list", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; @@ -84091,13 +84866,11 @@ pub mod builder { } } - /// Streams `GET` requests to - /// `/v1/multicast-groups/{multicast_group}/members` + /// Streams `GET` requests to `/v1/multicast-groups` pub fn stream( self, - ) -> impl futures::Stream>> - + Unpin - + 'a { + ) -> impl futures::Stream>> + Unpin + 'a + { use ::futures::StreamExt; use ::futures::TryFutureExt; use ::futures::TryStreamExt; @@ -84140,92 +84913,44 @@ pub mod builder { } } - /// Builder for [`ClientExperimentalExt::multicast_group_member_add`] + /// Builder for [`ClientExperimentalExt::multicast_group_view`] /// - /// [`ClientExperimentalExt::multicast_group_member_add`]: super::ClientExperimentalExt::multicast_group_member_add + /// [`ClientExperimentalExt::multicast_group_view`]: super::ClientExperimentalExt::multicast_group_view #[derive(Debug, Clone)] - pub struct MulticastGroupMemberAdd<'a> { + pub struct MulticastGroupView<'a> { client: &'a super::Client, - multicast_group: Result, - project: Result, String>, - body: Result, + multicast_group: Result, } - impl<'a> MulticastGroupMemberAdd<'a> { + impl<'a> MulticastGroupView<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, multicast_group: Err("multicast_group was not initialized".to_string()), - project: Ok(None), - body: Ok(::std::default::Default::default()), } } pub fn multicast_group(mut self, value: V) -> Self where - V: std::convert::TryInto, - { - self.multicast_group = value - .try_into() - .map_err(|_| "conversion to `NameOrId` for multicast_group failed".to_string()); - self - } - - pub fn project(mut self, value: V) -> Self - where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.project = value - .try_into() - .map(Some) - .map_err(|_| "conversion to `NameOrId` for project failed".to_string()); - self - } - - pub fn body(mut self, value: V) -> Self - where - V: std::convert::TryInto, - >::Error: std::fmt::Display, - { - self.body = value.try_into().map(From::from).map_err(|s| { - format!( - "conversion to `MulticastGroupMemberAdd` for body failed: {}", - s - ) + self.multicast_group = value.try_into().map_err(|_| { + "conversion to `MulticastGroupIdentifier` for multicast_group failed".to_string() }); self } - pub fn body_map(mut self, f: F) -> Self - where - F: std::ops::FnOnce( - types::builder::MulticastGroupMemberAdd, - ) -> types::builder::MulticastGroupMemberAdd, - { - self.body = self.body.map(f); - self - } - - /// Sends a `POST` request to - /// `/v1/multicast-groups/{multicast_group}/members` + /// Sends a `GET` request to `/v1/multicast-groups/{multicast_group}` pub async fn send( self, - ) -> Result, Error> { + ) -> Result, Error> { let Self { client, multicast_group, - project, - body, } = self; let multicast_group = multicast_group.map_err(Error::InvalidRequest)?; - let project = project.map_err(Error::InvalidRequest)?; - let body = body - .and_then(|v| { - types::MulticastGroupMemberAdd::try_from(v).map_err(|e| e.to_string()) - }) - .map_err(Error::InvalidRequest)?; let url = format!( - "{}/v1/multicast-groups/{}/members", + "{}/v1/multicast-groups/{}", client.baseurl, encode_path(&multicast_group.to_string()), ); @@ -84237,24 +84962,22 @@ pub mod builder { #[allow(unused_mut)] let mut request = client .client - .post(url) + .get(url) .header( ::reqwest::header::ACCEPT, ::reqwest::header::HeaderValue::from_static("application/json"), ) - .json(&body) - .query(&progenitor_client::QueryParam::new("project", &project)) .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "multicast_group_member_add", + operation_id: "multicast_group_view", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; client.post(&result, &info).await?; let response = result?; match response.status().as_u16() { - 201u16 => ResponseValue::from_response(response).await, + 200u16 => ResponseValue::from_response(response).await, 400u16..=499u16 => Err(Error::ErrorResponse( ResponseValue::from_response(response).await?, )), @@ -84266,75 +84989,91 @@ pub mod builder { } } - /// Builder for [`ClientExperimentalExt::multicast_group_member_remove`] + /// Builder for [`ClientExperimentalExt::multicast_group_member_list`] /// - /// [`ClientExperimentalExt::multicast_group_member_remove`]: super::ClientExperimentalExt::multicast_group_member_remove + /// [`ClientExperimentalExt::multicast_group_member_list`]: super::ClientExperimentalExt::multicast_group_member_list #[derive(Debug, Clone)] - pub struct MulticastGroupMemberRemove<'a> { + pub struct MulticastGroupMemberList<'a> { client: &'a super::Client, - multicast_group: Result, - instance: Result, - project: Result, String>, + multicast_group: Result, + limit: Result, String>, + page_token: Result, String>, + sort_by: Result, String>, } - impl<'a> MulticastGroupMemberRemove<'a> { + impl<'a> MulticastGroupMemberList<'a> { pub fn new(client: &'a super::Client) -> Self { Self { client: client, multicast_group: Err("multicast_group was not initialized".to_string()), - instance: Err("instance was not initialized".to_string()), - project: Ok(None), + limit: Ok(None), + page_token: Ok(None), + sort_by: Ok(None), } } pub fn multicast_group(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto, { - self.multicast_group = value - .try_into() - .map_err(|_| "conversion to `NameOrId` for multicast_group failed".to_string()); + self.multicast_group = value.try_into().map_err(|_| { + "conversion to `MulticastGroupIdentifier` for multicast_group failed".to_string() + }); self } - pub fn instance(mut self, value: V) -> Self + pub fn limit(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto<::std::num::NonZeroU32>, { - self.instance = value - .try_into() - .map_err(|_| "conversion to `NameOrId` for instance failed".to_string()); + self.limit = value.try_into().map(Some).map_err(|_| { + "conversion to `:: std :: num :: NonZeroU32` for limit failed".to_string() + }); self } - pub fn project(mut self, value: V) -> Self + pub fn page_token(mut self, value: V) -> Self where - V: std::convert::TryInto, + V: std::convert::TryInto<::std::string::String>, { - self.project = value + self.page_token = value.try_into().map(Some).map_err(|_| { + "conversion to `:: std :: string :: String` for page_token failed".to_string() + }); + self + } + + pub fn sort_by(mut self, value: V) -> Self + where + V: std::convert::TryInto, + { + self.sort_by = value .try_into() .map(Some) - .map_err(|_| "conversion to `NameOrId` for project failed".to_string()); + .map_err(|_| "conversion to `IdSortMode` for sort_by failed".to_string()); self } - /// Sends a `DELETE` request to - /// `/v1/multicast-groups/{multicast_group}/members/{instance}` - pub async fn send(self) -> Result, Error> { + /// Sends a `GET` request to + /// `/v1/multicast-groups/{multicast_group}/members` + pub async fn send( + self, + ) -> Result, Error> + { let Self { client, multicast_group, - instance, - project, + limit, + page_token, + sort_by, } = self; let multicast_group = multicast_group.map_err(Error::InvalidRequest)?; - let instance = instance.map_err(Error::InvalidRequest)?; - let project = project.map_err(Error::InvalidRequest)?; + let limit = limit.map_err(Error::InvalidRequest)?; + let page_token = page_token.map_err(Error::InvalidRequest)?; + let sort_by = sort_by.map_err(Error::InvalidRequest)?; let url = format!( - "{}/v1/multicast-groups/{}/members/{}", + "{}/v1/multicast-groups/{}/members", client.baseurl, encode_path(&multicast_group.to_string()), - encode_path(&instance.to_string()), ); let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); header_map.append( @@ -84344,23 +85083,28 @@ pub mod builder { #[allow(unused_mut)] let mut request = client .client - .delete(url) + .get(url) .header( ::reqwest::header::ACCEPT, ::reqwest::header::HeaderValue::from_static("application/json"), ) - .query(&progenitor_client::QueryParam::new("project", &project)) + .query(&progenitor_client::QueryParam::new("limit", &limit)) + .query(&progenitor_client::QueryParam::new( + "page_token", + &page_token, + )) + .query(&progenitor_client::QueryParam::new("sort_by", &sort_by)) .headers(header_map) .build()?; let info = OperationInfo { - operation_id: "multicast_group_member_remove", + operation_id: "multicast_group_member_list", }; client.pre(&mut request, &info).await?; let result = client.exec(request, &info).await; client.post(&result, &info).await?; let response = result?; match response.status().as_u16() { - 204u16 => Ok(ResponseValue::empty(response)), + 200u16 => ResponseValue::from_response(response).await, 400u16..=499u16 => Err(Error::ErrorResponse( ResponseValue::from_response(response).await?, )), @@ -84370,6 +85114,54 @@ pub mod builder { _ => Err(Error::UnexpectedResponse(response)), } } + + /// Streams `GET` requests to + /// `/v1/multicast-groups/{multicast_group}/members` + pub fn stream( + self, + ) -> impl futures::Stream>> + + Unpin + + 'a { + use ::futures::StreamExt; + use ::futures::TryFutureExt; + use ::futures::TryStreamExt; + let next = Self { + page_token: Ok(None), + sort_by: Ok(None), + ..self.clone() + }; + self.send() + .map_ok(move |page| { + let page = page.into_inner(); + let first = futures::stream::iter(page.items).map(Ok); + let rest = futures::stream::try_unfold( + (page.next_page, next), + |(next_page, next)| async { + if next_page.is_none() { + Ok(None) + } else { + Self { + page_token: Ok(next_page), + ..next.clone() + } + .send() + .map_ok(|page| { + let page = page.into_inner(); + Some(( + futures::stream::iter(page.items).map(Ok), + (page.next_page, next), + )) + }) + .await + } + }, + ) + .try_flatten(); + first.chain(rest) + }) + .try_flatten_stream() + .boxed() + } } /// Builder for [`ClientInstancesExt::instance_network_interface_list`] @@ -91641,80 +92433,6 @@ pub mod builder { } } - /// Builder for [`ClientExperimentalExt::lookup_multicast_group_by_ip`] - /// - /// [`ClientExperimentalExt::lookup_multicast_group_by_ip`]: super::ClientExperimentalExt::lookup_multicast_group_by_ip - #[derive(Debug, Clone)] - pub struct LookupMulticastGroupByIp<'a> { - client: &'a super::Client, - address: Result<::std::net::IpAddr, String>, - } - - impl<'a> LookupMulticastGroupByIp<'a> { - pub fn new(client: &'a super::Client) -> Self { - Self { - client: client, - address: Err("address was not initialized".to_string()), - } - } - - pub fn address(mut self, value: V) -> Self - where - V: std::convert::TryInto<::std::net::IpAddr>, - { - self.address = value.try_into().map_err(|_| { - "conversion to `:: std :: net :: IpAddr` for address failed".to_string() - }); - self - } - - /// Sends a `GET` request to - /// `/v1/system/multicast-groups/by-ip/{address}` - pub async fn send( - self, - ) -> Result, Error> { - let Self { client, address } = self; - let address = address.map_err(Error::InvalidRequest)?; - let url = format!( - "{}/v1/system/multicast-groups/by-ip/{}", - client.baseurl, - encode_path(&address.to_string()), - ); - let mut header_map = ::reqwest::header::HeaderMap::with_capacity(1usize); - header_map.append( - ::reqwest::header::HeaderName::from_static("api-version"), - ::reqwest::header::HeaderValue::from_static(super::Client::api_version()), - ); - #[allow(unused_mut)] - let mut request = client - .client - .get(url) - .header( - ::reqwest::header::ACCEPT, - ::reqwest::header::HeaderValue::from_static("application/json"), - ) - .headers(header_map) - .build()?; - let info = OperationInfo { - operation_id: "lookup_multicast_group_by_ip", - }; - client.pre(&mut request, &info).await?; - let result = client.exec(request, &info).await; - client.post(&result, &info).await?; - let response = result?; - match response.status().as_u16() { - 200u16 => ResponseValue::from_response(response).await, - 400u16..=499u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - 500u16..=599u16 => Err(Error::ErrorResponse( - ResponseValue::from_response(response).await?, - )), - _ => Err(Error::UnexpectedResponse(response)), - } - } - } - /// Builder for [`ClientSystemNetworkingExt::networking_address_lot_list`] /// /// [`ClientSystemNetworkingExt::networking_address_lot_list`]: super::ClientSystemNetworkingExt::networking_address_lot_list