diff --git a/nexus/mgs-updates/src/test_util/host_phase_2_test_state.rs b/nexus/mgs-updates/src/test_util/host_phase_2_test_state.rs index 80082e01377..54409f6a805 100644 --- a/nexus/mgs-updates/src/test_util/host_phase_2_test_state.rs +++ b/nexus/mgs-updates/src/test_util/host_phase_2_test_state.rs @@ -220,14 +220,13 @@ mod api_impl { use omicron_common::api::internal::shared::{ ResolvedVpcRouteSet, ResolvedVpcRouteState, SwitchPorts, }; - use sled_agent_api::v7::InstanceEnsureBody; - use sled_agent_api::v7::InstanceMulticastBody; use sled_agent_api::*; use sled_agent_types::bootstore::BootstoreStatus; use sled_agent_types::disk::DiskEnsureBody; use sled_agent_types::early_networking::EarlyNetworkConfig; use sled_agent_types::firewall_rules::VpcFirewallRulesEnsureBody; use sled_agent_types::instance::InstanceExternalIpBody; + use sled_agent_types::instance::InstanceMulticastBody; use sled_agent_types::instance::VmmPutStateBody; use sled_agent_types::instance::VmmPutStateResponse; use sled_agent_types::instance::VmmUnregisterResponse; @@ -531,7 +530,7 @@ mod api_impl { unimplemented!() } - async fn vmm_register_v1( + async fn vmm_register( _rqctx: RequestContext, _path_params: Path, _body: TypedBody, @@ -539,14 +538,6 @@ mod api_impl { unimplemented!() } - async fn vmm_register_v7( - _rqctx: RequestContext, - _path_params: Path, - _body: TypedBody, - ) -> Result, HttpError> { - unimplemented!() - } - async fn vmm_unregister( _rqctx: RequestContext, _path_params: Path, diff --git a/sled-agent/api/src/lib.rs b/sled-agent/api/src/lib.rs index d37f406af54..2465e504fd1 100644 --- a/sled-agent/api/src/lib.rs +++ b/sled-agent/api/src/lib.rs @@ -40,8 +40,8 @@ use sled_agent_types::{ early_networking::EarlyNetworkConfig, firewall_rules::VpcFirewallRulesEnsureBody, instance::{ - InstanceExternalIpBody, VmmPutStateBody, VmmPutStateResponse, - VmmUnregisterResponse, + InstanceExternalIpBody, InstanceMulticastBody, VmmPutStateBody, + VmmPutStateResponse, VmmUnregisterResponse, }, sled::AddSledRequest, zone_bundle::{ @@ -55,8 +55,8 @@ use uuid::Uuid; /// Copies of data types that changed between v3 and v4. mod v3; -/// Copies of data types that changed between previous versions and v7. -pub mod v7; +/// Copies of data types that changed between v6 and v7. +mod v6; api_versions!([ // WHEN CHANGING THE API (part 1 of 2): @@ -363,9 +363,9 @@ pub trait SledAgentApi { method = PUT, path = "/vmms/{propolis_id}", operation_id = "vmm_register", - versions = VERSION_INITIAL..VERSION_MULTICAST_SUPPORT + versions = VERSION_MULTICAST_SUPPORT.. }] - async fn vmm_register_v1( + async fn vmm_register( rqctx: RequestContext, path_params: Path, body: TypedBody, @@ -375,13 +375,15 @@ pub trait SledAgentApi { method = PUT, path = "/vmms/{propolis_id}", operation_id = "vmm_register", - versions = VERSION_MULTICAST_SUPPORT.. + versions = ..VERSION_MULTICAST_SUPPORT }] - async fn vmm_register_v7( + async fn v6_vmm_register( rqctx: RequestContext, path_params: Path, - body: TypedBody, - ) -> Result, HttpError>; + body: TypedBody, + ) -> Result, HttpError> { + Self::vmm_register(rqctx, path_params, body.map(Into::into)).await + } #[endpoint { method = DELETE, @@ -439,7 +441,7 @@ pub trait SledAgentApi { async fn vmm_join_multicast_group( rqctx: RequestContext, path_params: Path, - body: TypedBody, + body: TypedBody, ) -> Result; #[endpoint { @@ -450,7 +452,7 @@ pub trait SledAgentApi { async fn vmm_leave_multicast_group( rqctx: RequestContext, path_params: Path, - body: TypedBody, + body: TypedBody, ) -> Result; #[endpoint { diff --git a/sled-agent/api/src/v7.rs b/sled-agent/api/src/v6.rs similarity index 62% rename from sled-agent/api/src/v7.rs rename to sled-agent/api/src/v6.rs index 4e096e5415f..41adf5a464a 100644 --- a/sled-agent/api/src/v7.rs +++ b/sled-agent/api/src/v6.rs @@ -2,9 +2,9 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -//! Sled agent API types (version 7) +//! Sled agent types (version 6) //! -//! Version 7 adds support for multicast group management on instances. +//! Version 6 types (before multicast support was added in version 7). use std::net::{IpAddr, SocketAddr}; @@ -21,12 +21,11 @@ use omicron_common::api::{ use omicron_uuid_kinds::InstanceUuid; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use uuid::Uuid; - use sled_agent_types::instance::{InstanceMetadata, VmmSpec}; +use uuid::Uuid; /// The body of a request to ensure that a instance and VMM are known to a sled -/// agent (version 7, with multicast support). +/// agent (version 6, before multicast support). #[derive(Serialize, Deserialize, JsonSchema)] pub struct InstanceEnsureBody { /// The virtual hardware configuration this virtual machine should have when @@ -56,7 +55,7 @@ pub struct InstanceEnsureBody { } /// Describes sled-local configuration that a sled-agent must establish to make -/// the instance's virtual hardware fully functional (version 7, with multicast). +/// the instance's virtual hardware fully functional (version 6, before multicast). #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct InstanceSledLocalConfig { pub hostname: Hostname, @@ -66,25 +65,59 @@ pub struct InstanceSledLocalConfig { /// provided to an instance to allow inbound connectivity. pub ephemeral_ip: Option, pub floating_ips: Vec, - pub multicast_groups: Vec, pub firewall_rules: Vec, pub dhcp_config: DhcpConfig, } -/// Represents a multicast group membership for an instance. -#[derive( - Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, -)] -pub struct InstanceMulticastMembership { - pub group_ip: IpAddr, - // For Source-Specific Multicast (SSM) - pub sources: Vec, +impl From + for sled_agent_types::instance::InstanceSledLocalConfig +{ + fn from(v6: InstanceSledLocalConfig) -> Self { + let InstanceSledLocalConfig { + hostname, + nics, + source_nat, + ephemeral_ip, + floating_ips, + firewall_rules, + dhcp_config, + } = v6; + + Self { + hostname, + nics, + source_nat, + ephemeral_ip, + floating_ips, + multicast_groups: Vec::new(), + firewall_rules, + dhcp_config, + } + } } -/// Request body for multicast group operations. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum InstanceMulticastBody { - Join(InstanceMulticastMembership), - Leave(InstanceMulticastMembership), +impl From + for sled_agent_types::instance::InstanceEnsureBody +{ + fn from(v6: InstanceEnsureBody) -> Self { + let InstanceEnsureBody { + vmm_spec, + local_config, + vmm_runtime, + instance_id, + migration_id, + propolis_addr, + metadata, + } = v6; + + Self { + vmm_spec, + local_config: local_config.into(), + vmm_runtime, + instance_id, + migration_id, + propolis_addr, + metadata, + } + } } diff --git a/sled-agent/src/http_entrypoints.rs b/sled-agent/src/http_entrypoints.rs index a3c6a0ec92f..e772c8e90c7 100644 --- a/sled-agent/src/http_entrypoints.rs +++ b/sled-agent/src/http_entrypoints.rs @@ -32,8 +32,8 @@ use sled_agent_types::disk::DiskEnsureBody; use sled_agent_types::early_networking::EarlyNetworkConfig; use sled_agent_types::firewall_rules::VpcFirewallRulesEnsureBody; use sled_agent_types::instance::{ - InstanceExternalIpBody, VmmPutStateBody, VmmPutStateResponse, - VmmUnregisterResponse, + InstanceExternalIpBody, InstanceMulticastBody, VmmPutStateBody, + VmmPutStateResponse, VmmUnregisterResponse, }; use sled_agent_types::probes::ProbeSet; use sled_agent_types::sled::AddSledRequest; @@ -489,7 +489,7 @@ impl SledAgentApi for SledAgentImpl { Ok(HttpResponseOk(sa.get_role())) } - async fn vmm_register_v1( + async fn vmm_register( rqctx: RequestContext, path_params: Path, body: TypedBody, @@ -498,20 +498,7 @@ impl SledAgentApi for SledAgentImpl { let propolis_id = path_params.into_inner().propolis_id; let body_args = body.into_inner(); Ok(HttpResponseOk( - sa.instance_ensure_registered_v1(propolis_id, body_args).await?, - )) - } - - async fn vmm_register_v7( - rqctx: RequestContext, - path_params: Path, - body: TypedBody, - ) -> Result, HttpError> { - let sa = rqctx.context(); - let propolis_id = path_params.into_inner().propolis_id; - let body_args = body.into_inner(); - Ok(HttpResponseOk( - sa.instance_ensure_registered_v7(propolis_id, body_args).await?, + sa.instance_ensure_registered(propolis_id, body_args).await?, )) } @@ -571,7 +558,7 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_join_multicast_group( rqctx: RequestContext, path_params: Path, - body: TypedBody, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; @@ -583,7 +570,7 @@ impl SledAgentApi for SledAgentImpl { async fn vmm_leave_multicast_group( rqctx: RequestContext, path_params: Path, - body: TypedBody, + body: TypedBody, ) -> Result { let sa = rqctx.context(); let id = path_params.into_inner().propolis_id; diff --git a/sled-agent/src/instance.rs b/sled-agent/src/instance.rs index 9bb95964804..be4800c9b21 100644 --- a/sled-agent/src/instance.rs +++ b/sled-agent/src/instance.rs @@ -37,9 +37,6 @@ use propolis_client::Client as PropolisClient; use propolis_client::instance_spec::{ComponentV0, SpecKey}; use rand::SeedableRng; use rand::prelude::IteratorRandom; -use sled_agent_api::v7::{ - InstanceMulticastMembership, InstanceSledLocalConfig, -}; use sled_agent_config_reconciler::AvailableDatasetsReceiver; use sled_agent_types::instance::*; use sled_agent_types::zone_bundle::ZoneBundleCause; @@ -2491,11 +2488,11 @@ mod tests { use propolis_client::types::{ InstanceMigrateStatusResponse, InstanceStateMonitorResponse, }; - use sled_agent_api::v7::InstanceEnsureBody; use sled_agent_config_reconciler::{ CurrentlyManagedZpoolsReceiver, InternalDiskDetails, InternalDisksReceiver, }; + use sled_agent_types::instance::InstanceEnsureBody; use sled_agent_types::zone_bundle::CleanupContext; use sled_storage::config::MountConfig; use std::net::SocketAddrV6; diff --git a/sled-agent/src/instance_manager.rs b/sled-agent/src/instance_manager.rs index 540b71195a7..042db5e97d2 100644 --- a/sled-agent/src/instance_manager.rs +++ b/sled-agent/src/instance_manager.rs @@ -20,10 +20,10 @@ use omicron_common::api::external::ByteCount; use omicron_common::api::internal::nexus::SledVmmState; use omicron_common::api::internal::shared::SledIdentifiers; use omicron_uuid_kinds::PropolisUuid; -use sled_agent_api::v7::{InstanceEnsureBody, InstanceMulticastBody}; use sled_agent_config_reconciler::AvailableDatasetsReceiver; use sled_agent_config_reconciler::CurrentlyManagedZpoolsReceiver; use sled_agent_types::instance::*; +use sled_agent_types::instance::{InstanceEnsureBody, InstanceMulticastBody}; use slog::Logger; use std::collections::BTreeMap; use std::sync::Arc; diff --git a/sled-agent/src/sim/http_entrypoints.rs b/sled-agent/src/sim/http_entrypoints.rs index 94d0903f7a7..bcb729afba4 100644 --- a/sled-agent/src/sim/http_entrypoints.rs +++ b/sled-agent/src/sim/http_entrypoints.rs @@ -36,13 +36,13 @@ use omicron_common::api::internal::shared::{ ResolvedVpcRouteSet, ResolvedVpcRouteState, SwitchPorts, }; use range_requests::PotentialRange; -use sled_agent_api::v7::InstanceMulticastBody; use sled_agent_api::*; use sled_agent_types::bootstore::BootstoreStatus; use sled_agent_types::disk::DiskEnsureBody; use sled_agent_types::early_networking::EarlyNetworkConfig; use sled_agent_types::firewall_rules::VpcFirewallRulesEnsureBody; use sled_agent_types::instance::InstanceExternalIpBody; +use sled_agent_types::instance::InstanceMulticastBody; use sled_agent_types::instance::VmmPutStateBody; use sled_agent_types::instance::VmmPutStateResponse; use sled_agent_types::instance::VmmUnregisterResponse; @@ -82,23 +82,10 @@ enum SledAgentSimImpl {} impl SledAgentApi for SledAgentSimImpl { type Context = Arc; - async fn vmm_register_v1( + async fn vmm_register( rqctx: RequestContext, path_params: Path, body: TypedBody, - ) -> Result, HttpError> { - let sa = rqctx.context(); - let propolis_id = path_params.into_inner().propolis_id; - let body_args = body.into_inner(); - Ok(HttpResponseOk( - sa.instance_register_v1(propolis_id, body_args).await?, - )) - } - - async fn vmm_register_v7( - rqctx: RequestContext, - path_params: Path, - body: TypedBody, ) -> Result, HttpError> { let sa = rqctx.context(); let propolis_id = path_params.into_inner().propolis_id; diff --git a/sled-agent/src/sim/sled_agent.rs b/sled-agent/src/sim/sled_agent.rs index efda700b747..201509bf02c 100644 --- a/sled-agent/src/sim/sled_agent.rs +++ b/sled-agent/src/sim/sled_agent.rs @@ -56,14 +56,13 @@ use propolis_client::{ }; use range_requests::PotentialRange; use sled_agent_api::SupportBundleMetadata; -use sled_agent_api::v7::InstanceMulticastMembership; use sled_agent_types::disk::DiskStateRequested; use sled_agent_types::early_networking::{ EarlyNetworkConfig, EarlyNetworkConfigBody, }; use sled_agent_types::instance::{ - InstanceExternalIpBody, VmmPutStateResponse, VmmStateRequested, - VmmUnregisterResponse, + InstanceEnsureBody, InstanceExternalIpBody, InstanceMulticastMembership, + VmmPutStateResponse, VmmStateRequested, VmmUnregisterResponse, }; use slog::Logger; @@ -200,43 +199,12 @@ impl SledAgent { }) } - /// Idempotently ensures that the given API Instance (described by - /// `api_instance`) exists on this server in the given runtime state - /// (described by `target`). - // Keep the v1 method for compatibility but it just delegates to v2 - pub async fn instance_register_v1( - self: &Arc, - propolis_id: PropolisUuid, - instance: sled_agent_types::instance::InstanceEnsureBody, - ) -> Result { - // Convert v1 to v7 for internal processing - let v5_instance = sled_agent_api::v7::InstanceEnsureBody { - vmm_spec: instance.vmm_spec, - local_config: sled_agent_api::v7::InstanceSledLocalConfig { - hostname: instance.local_config.hostname, - nics: instance.local_config.nics, - source_nat: instance.local_config.source_nat, - ephemeral_ip: instance.local_config.ephemeral_ip, - floating_ips: instance.local_config.floating_ips, - multicast_groups: Vec::new(), // v1 doesn't support multicast - firewall_rules: instance.local_config.firewall_rules, - dhcp_config: instance.local_config.dhcp_config, - }, - vmm_runtime: instance.vmm_runtime, - instance_id: instance.instance_id, - migration_id: instance.migration_id, - propolis_addr: instance.propolis_addr, - metadata: instance.metadata, - }; - self.instance_register(propolis_id, v5_instance).await - } - pub async fn instance_register( self: &Arc, propolis_id: PropolisUuid, - instance: sled_agent_api::v7::InstanceEnsureBody, + instance: InstanceEnsureBody, ) -> Result { - let sled_agent_api::v7::InstanceEnsureBody { + let InstanceEnsureBody { vmm_spec, local_config, instance_id, @@ -722,7 +690,7 @@ impl SledAgent { pub async fn instance_join_multicast_group( &self, propolis_id: PropolisUuid, - membership: &sled_agent_api::v7::InstanceMulticastMembership, + membership: &InstanceMulticastMembership, ) -> Result<(), Error> { if !self.vmms.contains_key(&propolis_id.into_untyped_uuid()).await { return Err(Error::internal_error( @@ -741,7 +709,7 @@ impl SledAgent { pub async fn instance_leave_multicast_group( &self, propolis_id: PropolisUuid, - membership: &sled_agent_api::v7::InstanceMulticastMembership, + membership: &InstanceMulticastMembership, ) -> Result<(), Error> { if !self.vmms.contains_key(&propolis_id.into_untyped_uuid()).await { return Err(Error::internal_error( diff --git a/sled-agent/src/sled_agent.rs b/sled-agent/src/sled_agent.rs index d9a3e7c89b2..94ea67f271d 100644 --- a/sled-agent/src/sled_agent.rs +++ b/sled-agent/src/sled_agent.rs @@ -54,7 +54,6 @@ use omicron_ddm_admin_client::Client as DdmAdminClient; use omicron_uuid_kinds::{ GenericUuid, MupdateOverrideUuid, PropolisUuid, SledUuid, }; -use sled_agent_api::v7::{InstanceEnsureBody, InstanceMulticastBody}; use sled_agent_config_reconciler::{ ConfigReconcilerHandle, ConfigReconcilerSpawnToken, InternalDisks, InternalDisksReceiver, LedgerNewConfigError, LedgerTaskError, @@ -63,8 +62,8 @@ use sled_agent_config_reconciler::{ use sled_agent_types::disk::DiskStateRequested; use sled_agent_types::early_networking::EarlyNetworkConfig; use sled_agent_types::instance::{ - InstanceExternalIpBody, VmmPutStateResponse, VmmStateRequested, - VmmUnregisterResponse, + InstanceEnsureBody, InstanceExternalIpBody, InstanceMulticastBody, + VmmPutStateResponse, VmmStateRequested, VmmUnregisterResponse, }; use sled_agent_types::probes::ProbeCreate; use sled_agent_types::sled::{BaseboardId, StartSledAgentRequest}; @@ -842,42 +841,7 @@ impl SledAgent { /// Idempotently ensures that a given instance is registered with this sled, /// i.e., that it can be addressed by future calls to /// [`Self::instance_ensure_state`]. - pub async fn instance_ensure_registered_v1( - &self, - propolis_id: PropolisUuid, - instance: sled_agent_types::instance::InstanceEnsureBody, - ) -> Result { - // Convert v1 to v7 - let v5_instance = sled_agent_api::v7::InstanceEnsureBody { - vmm_spec: instance.vmm_spec, - local_config: sled_agent_api::v7::InstanceSledLocalConfig { - hostname: instance.local_config.hostname, - nics: instance.local_config.nics, - source_nat: instance.local_config.source_nat, - ephemeral_ip: instance.local_config.ephemeral_ip, - floating_ips: instance.local_config.floating_ips, - multicast_groups: Vec::new(), // v1 doesn't support multicast - firewall_rules: instance.local_config.firewall_rules, - dhcp_config: instance.local_config.dhcp_config, - }, - vmm_runtime: instance.vmm_runtime, - instance_id: instance.instance_id, - migration_id: instance.migration_id, - propolis_addr: instance.propolis_addr, - metadata: instance.metadata, - }; - self.instance_ensure_registered_v7(propolis_id, v5_instance).await - } - - pub async fn instance_ensure_registered_v7( - &self, - propolis_id: PropolisUuid, - instance: InstanceEnsureBody, - ) -> Result { - self.instance_ensure_registered(propolis_id, instance).await - } - - async fn instance_ensure_registered( + pub async fn instance_ensure_registered( &self, propolis_id: PropolisUuid, instance: InstanceEnsureBody, diff --git a/sled-agent/tests/multicast_cross_version_test.rs b/sled-agent/tests/multicast_cross_version_test.rs deleted file mode 100644 index b869e5a76e9..00000000000 --- a/sled-agent/tests/multicast_cross_version_test.rs +++ /dev/null @@ -1,118 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -//! Cross-version compatibility tests for sled-agent multicast APIs. -//! -//! This test verifies that v4 and v5 instance configurations work correctly -//! together, specifically around multicast group support. It follows the same -//! pattern as the DNS cross-version tests. - -use anyhow::Result; -use std::net::IpAddr; - -use omicron_common::api::internal::shared::DhcpConfig; -use sled_agent_api::v7; - -// Generate v5 client from v5 OpenAPI spec (with enhanced multicast support) -mod v5_client { - progenitor::generate_api!( - spec = "../openapi/sled-agent/sled-agent-5.0.0-253577.json", - interface = Positional, - inner_type = slog::Logger, - derives = [schemars::JsonSchema, Clone, Eq, PartialEq], - pre_hook = (|log: &slog::Logger, request: &reqwest::Request| { - slog::debug!(log, "client request"; - "method" => %request.method(), - "uri" => %request.url(), - "body" => ?&request.body(), - ); - }), - post_hook = (|log: &slog::Logger, result: &Result<_, _>| { - slog::debug!(log, "client response"; "result" => ?result); - }) - ); -} - -// A v5 server can productively handle requests from a v4 client, and a v4 -// client can provide instance configurations to a v5 server (backwards compatible). -// This follows the same pattern as DNS cross-version compatibility. -#[tokio::test] -pub async fn multicast_cross_version_works() -> Result<(), anyhow::Error> { - use omicron_test_utils::dev::test_setup_log; - let logctx = test_setup_log("multicast_cross_version_works"); - - let multicast_addr = "239.1.1.1".parse::().unwrap(); - let source_addr = "192.168.1.10".parse::().unwrap(); - - // Focus on the local_config field since that's where multicast_groups lives - - // Create v4 local config JSON (won't have multicast_groups field) - let v4_local_config_json = serde_json::json!({ - "hostname": "test-v4", - "nics": [], - "source_nat": { - "ip": "10.1.1.1", - "first_port": 0, - "last_port": 16383 - }, - "ephemeral_ip": null, - "floating_ips": [], - "firewall_rules": [], - "dhcp_config": { - "dns_servers": [], - "host_domain": null, - "search_domains": [] - } - }); - - // Create v5 local config with multicast_groups - let v5_local_config = v7::InstanceSledLocalConfig { - hostname: omicron_common::api::external::Hostname::try_from("test-v5") - .unwrap(), - nics: vec![], - source_nat: nexus_types::deployment::SourceNatConfig::new( - "10.1.1.1".parse().unwrap(), - 0, - 16383, - ) - .unwrap(), - ephemeral_ip: None, - floating_ips: vec![], - multicast_groups: vec![v7::InstanceMulticastMembership { - group_ip: multicast_addr, - sources: vec![source_addr], - }], - firewall_rules: vec![], - dhcp_config: DhcpConfig { - dns_servers: vec![], - host_domain: None, - search_domains: vec![], - }, - }; - - // Test that v4 can be parsed by v5 (with empty multicast_groups) - let v4_as_v5_json = serde_json::to_string(&v4_local_config_json)?; - let v5_json = serde_json::to_string(&v5_local_config)?; - - // v4 should NOT have multicast_groups in the JSON - assert!( - !v4_as_v5_json.contains("multicast_groups"), - "v4 InstanceSledLocalConfig should not contain multicast_groups field" - ); - - // v5 should HAVE multicast_groups in the JSON - assert!( - v5_json.contains("multicast_groups"), - "v5 InstanceSledLocalConfig should contain multicast_groups field" - ); - - // Verify v5 has the multicast group we added - assert!( - v5_json.contains(&format!("\"group_ip\":\"{multicast_addr}\"")), - "v5 should contain the multicast group IP" - ); - - logctx.cleanup_successful(); - Ok(()) -} diff --git a/sled-agent/types/src/instance.rs b/sled-agent/types/src/instance.rs index b2de8311dbb..b4acb39ce5d 100644 --- a/sled-agent/types/src/instance.rs +++ b/sled-agent/types/src/instance.rs @@ -68,10 +68,29 @@ pub struct InstanceSledLocalConfig { /// provided to an instance to allow inbound connectivity. pub ephemeral_ip: Option, pub floating_ips: Vec, + pub multicast_groups: Vec, pub firewall_rules: Vec, pub dhcp_config: DhcpConfig, } +/// Represents a multicast group membership for an instance. +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] +pub struct InstanceMulticastMembership { + pub group_ip: IpAddr, + // For Source-Specific Multicast (SSM) + pub sources: Vec, +} + +/// Request body for multicast group operations. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum InstanceMulticastBody { + Join(InstanceMulticastMembership), + Leave(InstanceMulticastMembership), +} + /// Metadata used to track statistics about an instance. /// // NOTE: The instance ID is not here, since it's already provided in other