diff --git a/nexus/db-queries/src/db/datastore/physical_disk.rs b/nexus/db-queries/src/db/datastore/physical_disk.rs index df710fb6ac4..01b8f6f18cb 100644 --- a/nexus/db-queries/src/db/datastore/physical_disk.rs +++ b/nexus/db-queries/src/db/datastore/physical_disk.rs @@ -774,9 +774,10 @@ mod test { use sled_agent_types::disk::DiskIdentity; use sled_agent_types::disk::DiskVariant; use sled_agent_types::inventory::{ - ConfigReconcilerInventoryStatus, FmdInventory, Inventory, - InventoryDisk, OmicronFileSourceResolverInventory, SledCpuFamily, - SledRole, SvcsEnabledNotOnlineResult, + ConfigReconcilerInventoryStatus, CurrentUpdateDisposition, + FmdInventory, InstanceManagerStatus, Inventory, InventoryDisk, + OmicronFileSourceResolverInventory, OmicronSledUpdateDisposition, + SledCpuFamily, SledRole, SvcsEnabledNotOnlineResult, }; use sled_hardware_types::BaseboardId; use std::num::NonZeroU32; @@ -1133,6 +1134,12 @@ mod test { reconciler_status: ConfigReconcilerInventoryStatus::NotYetRun, last_reconciliation: None, + instance_manager_status: InstanceManagerStatus { + update_disposition: CurrentUpdateDisposition::Known( + OmicronSledUpdateDisposition::Available, + ), + num_registered_vmms: 0, + }, file_source_resolver: OmicronFileSourceResolverInventory::new_fake(), smf_services_enabled_not_online: diff --git a/nexus/inventory/src/examples.rs b/nexus/inventory/src/examples.rs index fd93f264681..d508f625e5f 100644 --- a/nexus/inventory/src/examples.rs +++ b/nexus/inventory/src/examples.rs @@ -52,8 +52,10 @@ use sled_agent_types::inventory::BootPartitionDetails; use sled_agent_types::inventory::ConfigReconcilerInventory; use sled_agent_types::inventory::ConfigReconcilerInventoryResult; use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types::inventory::CurrentUpdateDisposition; use sled_agent_types::inventory::FmdInventory; use sled_agent_types::inventory::HostPhase2DesiredSlots; +use sled_agent_types::inventory::InstanceManagerStatus; use sled_agent_types::inventory::Inventory; use sled_agent_types::inventory::InventoryDataset; use sled_agent_types::inventory::InventoryDisk; @@ -1131,6 +1133,13 @@ pub fn sled_agent( }); let fmd = Ok(FmdInventory { cases: fmd_cases, resources: fmd_resources }); + let instance_manager_status = InstanceManagerStatus { + update_disposition: CurrentUpdateDisposition::Known( + OmicronSledUpdateDisposition::Available, + ), + num_registered_vmms: 3, + }; + Inventory { baseboard_id, reservoir_size: ByteCount::from(1024), @@ -1146,6 +1155,7 @@ pub fn sled_agent( ledgered_sled_config, reconciler_status, last_reconciliation, + instance_manager_status, file_source_resolver, smf_services_enabled_not_online, reference_measurements, 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 4df57e21773..abf9c7d7c5d 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 @@ -242,9 +242,11 @@ mod api_impl { use sled_agent_types::inventory::BootPartitionDetails; use sled_agent_types::inventory::ConfigReconcilerInventory; use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; + use sled_agent_types::inventory::CurrentUpdateDisposition; use sled_agent_types::inventory::FmdInventory; use sled_agent_types::inventory::HostPhase2DesiredContents; use sled_agent_types::inventory::HostPhase2DesiredSlots; + use sled_agent_types::inventory::InstanceManagerStatus; use sled_agent_types::inventory::Inventory; use sled_agent_types::inventory::ManifestInventory; use sled_agent_types::inventory::MupdateOverrideInventory; @@ -385,6 +387,12 @@ mod api_impl { remove_mupdate_override: None, boot_partitions, }), + instance_manager_status: InstanceManagerStatus { + update_disposition: CurrentUpdateDisposition::Known( + OmicronSledUpdateDisposition::Available, + ), + num_registered_vmms: 0, + }, fmd: Ok(FmdInventory::default()), file_source_resolver: OmicronFileSourceResolverInventory { zone_manifest: ManifestInventory { diff --git a/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs b/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs index 86efdb392c3..99151563ca0 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs @@ -34,8 +34,10 @@ use sled_agent_types::inventory::BootPartitionContents; use sled_agent_types::inventory::BootPartitionDetails; use sled_agent_types::inventory::ConfigReconcilerInventory; use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types::inventory::CurrentUpdateDisposition; use sled_agent_types::inventory::FmdInventory; use sled_agent_types::inventory::HostPhase2DesiredSlots; +use sled_agent_types::inventory::InstanceManagerStatus; use sled_agent_types::inventory::Inventory; use sled_agent_types::inventory::OmicronFileSourceResolverInventory; use sled_agent_types::inventory::OmicronSledConfig; @@ -1321,6 +1323,13 @@ impl<'a> TestBoardCollectionBuilder<'a> { ledgered_sled_config: Some(fake_sled_config), reconciler_status: ConfigReconcilerInventoryStatus::NotYetRun, + instance_manager_status: InstanceManagerStatus { + update_disposition: + CurrentUpdateDisposition::Known( + OmicronSledUpdateDisposition::Available, + ), + num_registered_vmms: 0, + }, file_source_resolver: OmicronFileSourceResolverInventory::new_fake(), smf_services_enabled_not_online: diff --git a/nexus/reconfigurator/planning/src/system.rs b/nexus/reconfigurator/planning/src/system.rs index d4c1a169e47..e1a1e9771e4 100644 --- a/nexus/reconfigurator/planning/src/system.rs +++ b/nexus/reconfigurator/planning/src/system.rs @@ -62,7 +62,9 @@ use sled_agent_types::disk::DiskVariant; use sled_agent_types::disk::M2Slot; use sled_agent_types::inventory::ConfigReconcilerInventory; use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types::inventory::CurrentUpdateDisposition; use sled_agent_types::inventory::FmdInventory; +use sled_agent_types::inventory::InstanceManagerStatus; use sled_agent_types::inventory::Inventory; use sled_agent_types::inventory::InventoryDataset; use sled_agent_types::inventory::InventoryDisk; @@ -71,6 +73,7 @@ use sled_agent_types::inventory::ManifestBootInventory; use sled_agent_types::inventory::MupdateOverrideBootInventory; use sled_agent_types::inventory::OmicronFileSourceResolverInventory; use sled_agent_types::inventory::OmicronSledConfig; +use sled_agent_types::inventory::OmicronSledUpdateDisposition; use sled_agent_types::inventory::SledCpuFamily; use sled_agent_types::inventory::SledRole; use sled_agent_types::inventory::SvcsEnabledNotOnlineResult; @@ -1518,6 +1521,12 @@ impl Sled { sled_config, ), ), + instance_manager_status: InstanceManagerStatus { + update_disposition: CurrentUpdateDisposition::Known( + OmicronSledUpdateDisposition::Available, + ), + num_registered_vmms: 0, + }, // XXX: return something more reasonable here? file_source_resolver: OmicronFileSourceResolverInventory::new_fake(), @@ -1704,6 +1713,12 @@ impl Sled { ledgered_sled_config: inv_sled_agent.ledgered_sled_config.clone(), reconciler_status: inv_sled_agent.reconciler_status.clone(), last_reconciliation: inv_sled_agent.last_reconciliation.clone(), + instance_manager_status: InstanceManagerStatus { + update_disposition: CurrentUpdateDisposition::Known( + OmicronSledUpdateDisposition::Available, + ), + num_registered_vmms: 0, + }, file_source_resolver: inv_sled_agent.file_source_resolver.clone(), smf_services_enabled_not_online: inv_sled_agent .smf_services_enabled_not_online diff --git a/nexus/src/app/update.rs b/nexus/src/app/update.rs index 2ea4076471d..5af80cb0b3c 100644 --- a/nexus/src/app/update.rs +++ b/nexus/src/app/update.rs @@ -919,10 +919,13 @@ mod test { use omicron_uuid_kinds::ZpoolUuid; use sled_agent_types::disk::M2Slot; use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; + use sled_agent_types::inventory::CurrentUpdateDisposition; use sled_agent_types::inventory::FmdInventory; + use sled_agent_types::inventory::InstanceManagerStatus; use sled_agent_types::inventory::Inventory; use sled_agent_types::inventory::InventoryZpool; use sled_agent_types::inventory::OmicronFileSourceResolverInventory; + use sled_agent_types::inventory::OmicronSledUpdateDisposition; use sled_agent_types::inventory::SledCpuFamily; use sled_agent_types::inventory::SledRole; use sled_agent_types::inventory::SvcEnabledNotOnline; @@ -962,6 +965,12 @@ mod test { ledgered_sled_config: None, reconciler_status: ConfigReconcilerInventoryStatus::NotYetRun, last_reconciliation: None, + instance_manager_status: InstanceManagerStatus { + update_disposition: CurrentUpdateDisposition::Known( + OmicronSledUpdateDisposition::Available, + ), + num_registered_vmms: 0, + }, file_source_resolver: OmicronFileSourceResolverInventory::new_fake( ), smf_services_enabled_not_online: smf_services, diff --git a/openapi/sled-agent/sled-agent-51.0.0-9a12e4.json.gitstub b/openapi/sled-agent/sled-agent-51.0.0-9a12e4.json.gitstub new file mode 100644 index 00000000000..e23cab20988 --- /dev/null +++ b/openapi/sled-agent/sled-agent-51.0.0-9a12e4.json.gitstub @@ -0,0 +1 @@ +cb538d50fc99c594c0eecb8e8a577b874dac37d1:openapi/sled-agent/sled-agent-51.0.0-9a12e4.json diff --git a/openapi/sled-agent/sled-agent-51.0.0-9a12e4.json b/openapi/sled-agent/sled-agent-52.0.0-fdb190.json similarity index 99% rename from openapi/sled-agent/sled-agent-51.0.0-9a12e4.json rename to openapi/sled-agent/sled-agent-52.0.0-fdb190.json index 9d4df1e4c3d..202ed6f3b70 100644 --- a/openapi/sled-agent/sled-agent-51.0.0-9a12e4.json +++ b/openapi/sled-agent/sled-agent-52.0.0-fdb190.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "51.0.0" + "version": "52.0.0" }, "paths": { "/artifacts": { @@ -4857,6 +4857,42 @@ ], "additionalProperties": false }, + "CurrentUpdateDisposition": { + "oneOf": [ + { + "type": "object", + "properties": { + "disposition": { + "type": "string", + "enum": [ + "config_not_available" + ] + } + }, + "required": [ + "disposition" + ] + }, + { + "type": "object", + "properties": { + "disposition": { + "type": "string", + "enum": [ + "known" + ] + }, + "value": { + "$ref": "#/components/schemas/OmicronSledUpdateDisposition" + } + }, + "required": [ + "disposition", + "value" + ] + } + ] + }, "DatasetConfig": { "description": "Configuration information necessary to request a single dataset.\n\nThese datasets are tracked directly by Nexus.", "type": "object", @@ -5907,6 +5943,23 @@ } ] }, + "InstanceManagerStatus": { + "type": "object", + "properties": { + "num_registered_vmms": { + "type": "integer", + "format": "uint", + "minimum": 0 + }, + "update_disposition": { + "$ref": "#/components/schemas/CurrentUpdateDisposition" + } + }, + "required": [ + "num_registered_vmms", + "update_disposition" + ] + }, "InstanceMetadata": { "description": "Metadata used to track statistics about an instance.", "type": "object", @@ -6205,6 +6258,9 @@ } ] }, + "instance_manager_status": { + "$ref": "#/components/schemas/InstanceManagerStatus" + }, "last_reconciliation": { "nullable": true, "allOf": [ @@ -6279,6 +6335,7 @@ "disks", "file_source_resolver", "fmd", + "instance_manager_status", "reconciler_status", "reference_measurements", "reservoir_size", diff --git a/openapi/sled-agent/sled-agent-latest.json b/openapi/sled-agent/sled-agent-latest.json index 708f8bce0e2..03b767c837c 120000 --- a/openapi/sled-agent/sled-agent-latest.json +++ b/openapi/sled-agent/sled-agent-latest.json @@ -1 +1 @@ -sled-agent-51.0.0-9a12e4.json \ No newline at end of file +sled-agent-52.0.0-fdb190.json \ No newline at end of file diff --git a/sled-agent/api/src/lib.rs b/sled-agent/api/src/lib.rs index 9e287fdfdb8..951bfe6e2ae 100644 --- a/sled-agent/api/src/lib.rs +++ b/sled-agent/api/src/lib.rs @@ -22,7 +22,7 @@ use omicron_common::api::internal::{ use sled_agent_types_versions::{ latest, v1, v4, v6, v7, v9, v10, v11, v12, v14, v16, v17, v18, v20, v22, v24, v25, v26, v28, v29, v30, v31, v32, v33, v34, v37, v39, v40, v41, v42, - v43, v46, v47, v48, v49, v50, + v43, v46, v47, v48, v49, v50, v51, }; use sled_diagnostics::SledDiagnosticsQueryOutput; use slog_error_chain::InlineErrorChain; @@ -39,6 +39,7 @@ api_versions!([ // | example for the next person. // v // (next_int, IDENT), + (52, ADD_INSTANCE_MANAGER_STATUS_TO_INVENTORY), (51, MULTIPLE_ZONE_EXTERNAL_IPS), (50, TYPED_SLED_CONFIG_GENERATION), (49, ADD_UPDATE_DISPOSITION), @@ -1200,7 +1201,7 @@ pub trait SledAgentApi { #[endpoint { method = GET, path = "/inventory", - versions = VERSION_MULTIPLE_ZONE_EXTERNAL_IPS.., + versions = VERSION_ADD_INSTANCE_MANAGER_STATUS_TO_INVENTORY.., }] async fn inventory( rqctx: RequestContext, @@ -1208,6 +1209,22 @@ pub trait SledAgentApi { /// Fetch basic information about this sled #[endpoint { + operation_id = "inventory", + method = GET, + path = "/inventory", + versions = VERSION_MULTIPLE_ZONE_EXTERNAL_IPS..VERSION_ADD_INSTANCE_MANAGER_STATUS_TO_INVENTORY, + }] + async fn inventory_v51( + rqctx: RequestContext, + ) -> Result, HttpError> { + Self::inventory(rqctx).await.map(|HttpResponseOk(inv)| { + HttpResponseOk(v51::inventory::Inventory::from(inv)) + }) + } + + /// Fetch basic information about this sled + #[endpoint { + operation_id = "inventory", method = GET, path = "/inventory", versions = VERSION_TYPED_SLED_CONFIG_GENERATION..VERSION_MULTIPLE_ZONE_EXTERNAL_IPS, @@ -1215,7 +1232,7 @@ pub trait SledAgentApi { async fn inventory_v50( rqctx: RequestContext, ) -> Result, HttpError> { - let HttpResponseOk(inv) = Self::inventory(rqctx).await?; + let HttpResponseOk(inv) = Self::inventory_v51(rqctx).await?; v50::inventory::Inventory::try_from(inv) .map(HttpResponseOk) .map_err(HttpError::from) diff --git a/sled-agent/config-reconciler/src/handle.rs b/sled-agent/config-reconciler/src/handle.rs index d37ea02360f..5e949116679 100644 --- a/sled-agent/config-reconciler/src/handle.rs +++ b/sled-agent/config-reconciler/src/handle.rs @@ -9,11 +9,11 @@ use omicron_common::disk::DatasetName; use sled_agent_types::artifact::ArtifactConfig; use sled_agent_types::inventory::ConfigReconcilerInventory; use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types::inventory::CurrentUpdateDisposition; use sled_agent_types::inventory::InventoryDataset; use sled_agent_types::inventory::InventoryDisk; use sled_agent_types::inventory::InventoryZpool; use sled_agent_types::inventory::OmicronSledConfig; -use sled_agent_types::inventory::OmicronSledUpdateDisposition; use sled_storage::config::MountConfig; use sled_storage::disk::Disk; use sled_storage::nested_dataset::NestedDatasetConfig; @@ -116,13 +116,6 @@ impl ConfigReconcilerSpawnToken { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(any(test, feature = "testing"), derive(test_strategy::Arbitrary))] -pub enum CurrentUpdateDisposition { - ConfigNotAvailable, - Known(OmicronSledUpdateDisposition), -} - #[derive(Debug, Clone)] pub struct UpdateDispositionReceiver { // We act as a forwarding watch receiver for the ledger channel that reports @@ -175,7 +168,7 @@ impl UpdateDispositionReceiver { /// never change. #[cfg(any(test, feature = "testing"))] pub fn fake_static( - update_disposition: OmicronSledUpdateDisposition, + update_disposition: sled_agent_types::inventory::OmicronSledUpdateDisposition, ) -> Self { let (receiver, sender) = Self::fake_dynamic( CurrentUpdateDisposition::Known(update_disposition), diff --git a/sled-agent/config-reconciler/src/lib.rs b/sled-agent/config-reconciler/src/lib.rs index 9bb0c0435dc..3e8b292e764 100644 --- a/sled-agent/config-reconciler/src/lib.rs +++ b/sled-agent/config-reconciler/src/lib.rs @@ -65,7 +65,6 @@ pub use dataset_serialization_task::NestedDatasetMountError; pub use handle::AvailableDatasetsReceiver; pub use handle::ConfigReconcilerHandle; pub use handle::ConfigReconcilerSpawnToken; -pub use handle::CurrentUpdateDisposition; pub use handle::InventoryError; pub use handle::ReconcilerInventory; pub use handle::TimeSyncConfig; diff --git a/sled-agent/rack-setup/src/plan/service.rs b/sled-agent/rack-setup/src/plan/service.rs index f9c68900a13..624c9dcd5af 100644 --- a/sled-agent/rack-setup/src/plan/service.rs +++ b/sled-agent/rack-setup/src/plan/service.rs @@ -1395,8 +1395,11 @@ mod tests { use sled_agent_types::early_networking::RackNetworkConfig; use sled_agent_types::early_networking::UplinkPorts; use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; + use sled_agent_types::inventory::CurrentUpdateDisposition; use sled_agent_types::inventory::FmdInventory; + use sled_agent_types::inventory::InstanceManagerStatus; use sled_agent_types::inventory::OmicronFileSourceResolverInventory; + use sled_agent_types::inventory::OmicronSledUpdateDisposition; use sled_agent_types::inventory::SledCpuFamily; use sled_agent_types::inventory::SvcsEnabledNotOnlineResult; use sled_hardware_types::BaseboardId; @@ -1615,6 +1618,12 @@ mod tests { ledgered_sled_config: None, reconciler_status: ConfigReconcilerInventoryStatus::NotYetRun, last_reconciliation: None, + instance_manager_status: InstanceManagerStatus { + update_disposition: CurrentUpdateDisposition::Known( + OmicronSledUpdateDisposition::Available, + ), + num_registered_vmms: 0, + }, file_source_resolver: OmicronFileSourceResolverInventory::new_fake(), smf_services_enabled_not_online: diff --git a/sled-agent/rack-setup/src/service.rs b/sled-agent/rack-setup/src/service.rs index 3f97dd4e1f7..4e980164ceb 100644 --- a/sled-agent/rack-setup/src/service.rs +++ b/sled-agent/rack-setup/src/service.rs @@ -1644,6 +1644,8 @@ mod test { use oxnet::Ipv6Net; use sled_agent_types::disk::DiskIdentity; use sled_agent_types::disk::DiskVariant; + use sled_agent_types::inventory::CurrentUpdateDisposition; + use sled_agent_types::inventory::InstanceManagerStatus; use sled_agent_types::{ early_networking::{PortConfig, RackNetworkConfig, UplinkPorts}, inventory::{ @@ -1708,6 +1710,12 @@ mod test { ledgered_sled_config: None, reconciler_status: ConfigReconcilerInventoryStatus::NotYetRun, last_reconciliation: None, + instance_manager_status: InstanceManagerStatus { + update_disposition: CurrentUpdateDisposition::Known( + OmicronSledUpdateDisposition::Available, + ), + num_registered_vmms: 0, + }, file_source_resolver: OmicronFileSourceResolverInventory::new_fake(), smf_services_enabled_not_online: diff --git a/sled-agent/src/instance.rs b/sled-agent/src/instance.rs index 08bbcbb033c..c9a9b9f385c 100644 --- a/sled-agent/src/instance.rs +++ b/sled-agent/src/instance.rs @@ -2761,9 +2761,7 @@ impl InstanceRunner { mod tests { use super::*; use crate::fakes::nexus::{FakeNexusServer, ServerContext}; - use crate::instance_manager::{ - InstanceManagerJobsStatus, VmmRegistrationDisallowedReason, - }; + use crate::instance_manager::VmmRegistrationDisallowedReason; use crate::metrics; use crate::nexus::make_nexus_client_with_port; use crate::vmm_reservoir::VmmReservoirManagerHandle; @@ -2784,13 +2782,15 @@ mod tests { }; use sled_agent_config_reconciler::UpdateDispositionReceiver; use sled_agent_config_reconciler::{ - CurrentUpdateDisposition, CurrentlyManagedZpoolsReceiver, - InternalDiskDetails, InternalDisksReceiver, + CurrentlyManagedZpoolsReceiver, InternalDiskDetails, + InternalDisksReceiver, }; use sled_agent_types::disk::DiskIdentity; use sled_agent_types::instance::ExternalIpv4Config; use sled_agent_types::instance::ExternalIpv6Config; use sled_agent_types::instance::InstanceEnsureBody; + use sled_agent_types::inventory::CurrentUpdateDisposition; + use sled_agent_types::inventory::InstanceManagerStatus; use sled_agent_types::inventory::OmicronSledUpdateDisposition; use sled_agent_types::inventory::SourceNatConfigV6; use sled_agent_types::zone_bundle::CleanupContext; @@ -3591,15 +3591,15 @@ mod tests { .await } - /// Wait (with a timeout) until the `InstanceManager`'s jobs status - /// satisfies `pred`. - async fn wait_for_jobs_status( + /// Wait (with a timeout) until the `InstanceManager`'s status satisfies + /// `pred`. + async fn wait_for_status( instance_manager: &crate::instance_manager::InstanceManager, - pred: fn(&InstanceManagerJobsStatus) -> bool, + pred: fn(&InstanceManagerStatus) -> bool, ) { wait_for_condition( || async { - let status = instance_manager.jobs_status(); + let status = instance_manager.status(); if pred(&status) { Ok(()) } else { @@ -3646,7 +3646,7 @@ mod tests { ) ); - let status = test_objects.instance_manager.jobs_status(); + let status = test_objects.instance_manager.status(); assert_eq!(status.num_registered_vmms, 0); assert_eq!( status.update_disposition, @@ -3695,7 +3695,7 @@ mod tests { disposition_tx.set(CurrentUpdateDisposition::Known( OmicronSledUpdateDisposition::Available, )); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.update_disposition == CurrentUpdateDisposition::Known( OmicronSledUpdateDisposition::Available, @@ -3706,7 +3706,7 @@ mod tests { try_ensure_registered(&test_objects, propolis_id, instance_id) .await .expect("registration should succeed once the sled is available"); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.num_registered_vmms == 1 }) .await; @@ -3736,7 +3736,7 @@ mod tests { try_ensure_registered(&test_objects, propolis_id_a, instance_id_a) .await .expect("registration should succeed while available"); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.num_registered_vmms == 1 }) .await; @@ -3744,7 +3744,7 @@ mod tests { disposition_tx.set(CurrentUpdateDisposition::Known( OmicronSledUpdateDisposition::Evacuating, )); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.update_disposition == CurrentUpdateDisposition::Known( OmicronSledUpdateDisposition::Evacuating, @@ -3758,7 +3758,7 @@ mod tests { .await .expect("re-registration should succeed while evacuating"); assert_eq!( - test_objects.instance_manager.jobs_status().num_registered_vmms, + test_objects.instance_manager.status().num_registered_vmms, 1 ); @@ -3778,7 +3778,7 @@ mod tests { ) ); assert_eq!( - test_objects.instance_manager.jobs_status().num_registered_vmms, + test_objects.instance_manager.status().num_registered_vmms, 1 ); @@ -3786,7 +3786,7 @@ mod tests { disposition_tx.set(CurrentUpdateDisposition::Known( OmicronSledUpdateDisposition::Available, )); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.update_disposition == CurrentUpdateDisposition::Known( OmicronSledUpdateDisposition::Available, @@ -3796,7 +3796,7 @@ mod tests { try_ensure_registered(&test_objects, propolis_id_b, instance_id_b) .await .expect("registration should succeed once available again"); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.num_registered_vmms == 2 }) .await; @@ -3818,7 +3818,7 @@ mod tests { try_ensure_registered(&test_objects, propolis_id_a, instance_id_a) .await .expect("registration A should succeed"); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.num_registered_vmms == 1 }) .await; @@ -3831,7 +3831,7 @@ mod tests { ) .await .expect("registration B should succeed"); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.num_registered_vmms == 2 }) .await; @@ -3841,7 +3841,7 @@ mod tests { .await .expect("re-registration A should succeed"); assert_eq!( - test_objects.instance_manager.jobs_status().num_registered_vmms, + test_objects.instance_manager.status().num_registered_vmms, 2 ); @@ -3850,7 +3850,7 @@ mod tests { .ensure_unregistered(propolis_id_a) .await .expect("unregistration A should succeed"); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.num_registered_vmms == 1 }) .await; @@ -3860,7 +3860,7 @@ mod tests { .ensure_unregistered(propolis_id_b) .await .expect("unregistration B should succeed"); - wait_for_jobs_status(&test_objects.instance_manager, |status| { + wait_for_status(&test_objects.instance_manager, |status| { status.num_registered_vmms == 0 }) .await; diff --git a/sled-agent/src/instance_manager.rs b/sled-agent/src/instance_manager.rs index e53b62f9cd7..efa7563c17f 100644 --- a/sled-agent/src/instance_manager.rs +++ b/sled-agent/src/instance_manager.rs @@ -26,6 +26,7 @@ use sled_agent_config_reconciler::UpdateDispositionReceiver; use sled_agent_types::attached_subnet::AttachedSubnet; use sled_agent_types::attached_subnet::AttachedSubnets; use sled_agent_types::instance::*; +use sled_agent_types::inventory::InstanceManagerStatus; use slog::Logger; use slog_error_chain::InlineErrorChain; use std::sync::Arc; @@ -38,8 +39,6 @@ use self::jobs::CanEnsureVmm; use self::jobs::InstanceManagerJobsStatusReceiver; use self::jobs::Jobs; -pub(crate) use self::jobs::InstanceManagerJobsStatus; - // The depth of the request queue for the instance manager. const QUEUE_SIZE: usize = 256; @@ -228,9 +227,9 @@ impl InstanceManager { }) } - // TODO: Plumb this status through inventory. Part of omicron#11121. - #[allow(unused)] - pub fn jobs_status(&self) -> InstanceManagerJobsStatus { + pub fn status(&self) -> InstanceManagerStatus { + // For now, the only meaningful status we report to inventory is the + // status of our `jobs` map. self.jobs_status_rx.read() } diff --git a/sled-agent/src/instance_manager/jobs.rs b/sled-agent/src/instance_manager/jobs.rs index 39afe3dd749..8a7e37a93b1 100644 --- a/sled-agent/src/instance_manager/jobs.rs +++ b/sled-agent/src/instance_manager/jobs.rs @@ -7,26 +7,21 @@ use crate::instance::Instance; use crate::instance_manager::VmmRegistrationDisallowedReason; use omicron_uuid_kinds::PropolisUuid; -use sled_agent_config_reconciler::CurrentUpdateDisposition; +use sled_agent_types::inventory::CurrentUpdateDisposition; +use sled_agent_types::inventory::InstanceManagerStatus; use sled_agent_types::inventory::OmicronSledUpdateDisposition; use std::collections::BTreeMap; use std::collections::btree_map; use std::sync::Arc; use std::sync::RwLock; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct InstanceManagerJobsStatus { - pub update_disposition: CurrentUpdateDisposition, - pub num_registered_vmms: usize, -} - #[derive(Debug)] pub struct InstanceManagerJobsStatusReceiver { - status: Arc>, + status: Arc>, } impl InstanceManagerJobsStatusReceiver { - pub fn read(&self) -> InstanceManagerJobsStatus { + pub fn read(&self) -> InstanceManagerStatus { *self.status.read().unwrap() } } @@ -66,12 +61,12 @@ pub(super) struct Jobs { // `RegisterNewVmm::insert()` below, which always update `status` when // modifying the contents of `jobs`. jobs: BTreeMap, - status: Arc>, + status: Arc>, } impl Jobs { pub(super) fn new(update_disposition: CurrentUpdateDisposition) -> Self { - let status = Arc::new(RwLock::new(InstanceManagerJobsStatus { + let status = Arc::new(RwLock::new(InstanceManagerStatus { update_disposition, num_registered_vmms: 0, })); @@ -144,7 +139,7 @@ impl Jobs { #[derive(Debug)] pub(super) struct RegisterNewVmm<'a, T> { entry: btree_map::VacantEntry<'a, PropolisUuid, T>, - status: &'a RwLock, + status: &'a RwLock, } impl<'a, T> RegisterNewVmm<'a, T> { diff --git a/sled-agent/src/sim/http_entrypoints.rs b/sled-agent/src/sim/http_entrypoints.rs index 1d513c37e4a..4c6ed28136c 100644 --- a/sled-agent/src/sim/http_entrypoints.rs +++ b/sled-agent/src/sim/http_entrypoints.rs @@ -583,7 +583,7 @@ impl SledAgentApi for SledAgentSimImpl { ) -> Result, HttpError> { let sa = rqctx.context(); Ok(HttpResponseOk( - sa.inventory(rqctx.server.local_addr).map_err(|e| { + sa.inventory(rqctx.server.local_addr).await.map_err(|e| { HttpError::for_internal_error(format!("{:#}", e)) })?, )) diff --git a/sled-agent/src/sim/server.rs b/sled-agent/src/sim/server.rs index 79f7a7c7c09..c4fa15562da 100644 --- a/sled-agent/src/sim/server.rs +++ b/sled-agent/src/sim/server.rs @@ -647,7 +647,8 @@ pub async fn run_standalone_server( .expect("no zones are included in the plan"), ); - let inventory = server.sled_agent.inventory(underlay_address.into())?; + let inventory = + server.sled_agent.inventory(underlay_address.into()).await?; let mut all_sleds = IdOrdMap::new(); all_sleds.insert_overwrite(PlannedSledDescription { underlay_address, diff --git a/sled-agent/src/sim/sled_agent.rs b/sled-agent/src/sim/sled_agent.rs index f2a62aba68d..de7e4591e57 100644 --- a/sled-agent/src/sim/sled_agent.rs +++ b/sled-agent/src/sim/sled_agent.rs @@ -60,10 +60,11 @@ use sled_agent_types::instance::{ }; use sled_agent_types::inventory::{ ConfigReconcilerInventory, ConfigReconcilerInventoryResult, - ConfigReconcilerInventoryStatus, FmdInventory, Inventory, InventoryDataset, - InventoryDisk, InventoryZpool, OmicronFileSourceResolverInventory, - OmicronSledConfig, OmicronSledUpdateDisposition, - SingleMeasurementInventory, SledRole, ZpoolHealth, + ConfigReconcilerInventoryStatus, CurrentUpdateDisposition, FmdInventory, + InstanceManagerStatus, Inventory, InventoryDataset, InventoryDisk, + InventoryZpool, OmicronFileSourceResolverInventory, OmicronSledConfig, + OmicronSledUpdateDisposition, SingleMeasurementInventory, SledRole, + ZpoolHealth, }; use sled_agent_types::support_bundle::SupportBundleMetadata; use sled_agent_types::system_networking::SystemNetworkingConfig; @@ -895,7 +896,10 @@ impl SledAgent { Ok(addr) } - pub fn inventory(&self, addr: SocketAddr) -> anyhow::Result { + pub async fn inventory( + &self, + addr: SocketAddr, + ) -> anyhow::Result { let sled_agent_address = match addr { SocketAddr::V4(_) => { bail!("sled_agent_ip must be v6 for inventory") @@ -903,6 +907,14 @@ impl SledAgent { SocketAddr::V6(v6) => v6, }; + // TODO-correctness Unlike real sled-agent, the `InstanceManagerStatus` + // we report view is _not_ atomic - we acquire separate locks to fill + // the number of VMMs and the update disposition. If that becomes + // problematic in tests, we'll need to combine these (probably by moving + // the disposition into `self.vmms`, which is how sled-agent proper + // handles this). + let num_registered_vmms = self.vmms.size().await; + let storage = self.storage.lock(); let maybe_sled_config = storage.omicron_sled_config(); @@ -924,6 +936,19 @@ impl SledAgent { .into_iter() .collect(); + let instance_manager_status = InstanceManagerStatus { + update_disposition: match maybe_sled_config + .as_ref() + .map(|c| c.update_disposition) + { + Some(disposition) => { + CurrentUpdateDisposition::Known(disposition) + } + None => CurrentUpdateDisposition::ConfigNotAvailable, + }, + num_registered_vmms, + }; + Ok(Inventory { sled_id: self.id, sled_agent_address, @@ -994,6 +1019,7 @@ impl SledAgent { }, last_reconciliation: maybe_sled_config .map(ConfigReconcilerInventory::debug_assume_success), + instance_manager_status, // TODO: simulate the file source resolver with greater fidelity file_source_resolver: OmicronFileSourceResolverInventory::new_fake( ), diff --git a/sled-agent/src/sled_agent.rs b/sled-agent/src/sled_agent.rs index f354b6835a6..186809309c4 100644 --- a/sled-agent/src/sled_agent.rs +++ b/sled-agent/src/sled_agent.rs @@ -1391,6 +1391,7 @@ impl SledAgent { reconciler_status, last_reconciliation, file_source_resolver, + instance_manager_status: self.inner.instances.status(), smf_services_enabled_not_online, reference_measurements: self.inner.measurements.to_inventory(), fmd, diff --git a/sled-agent/types/versions/src/add_instance_manager_status_to_inventory/inventory.rs b/sled-agent/types/versions/src/add_instance_manager_status_to_inventory/inventory.rs new file mode 100644 index 00000000000..a0c95eaaa24 --- /dev/null +++ b/sled-agent/types/versions/src/add_instance_manager_status_to_inventory/inventory.rs @@ -0,0 +1,122 @@ +// 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/. + +use crate::v1::inventory::InventoryDataset; +use crate::v1::inventory::InventoryDisk; +use crate::v1::inventory::SledRole; +use crate::v14::inventory::OmicronFileSourceResolverInventory; +use crate::v16::inventory::SingleMeasurementInventory; +use crate::v24::inventory::InventoryZpool; +use crate::v40::inventory::FmdInventory; +use crate::v40::inventory::FmdInventoryError; +use crate::v46::inventory::SvcsEnabledNotOnlineResult; +use crate::v49::inventory::OmicronSledUpdateDisposition; +use crate::v51::inventory::ConfigReconcilerInventory; +use crate::v51::inventory::ConfigReconcilerInventoryStatus; +use crate::v51::inventory::OmicronSledConfig; +use iddqd::IdOrdMap; +use omicron_common::api::external::ByteCount; +use omicron_common::snake_case_result; +use omicron_common::snake_case_result::SnakeCaseResult; +use omicron_uuid_kinds::SledUuid; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use sled_hardware_types::BaseboardId; +use sled_hardware_types::SledCpuFamily; +use std::net::SocketAddrV6; + +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, +)] +#[serde(tag = "disposition", rename_all = "snake_case", content = "value")] +#[cfg_attr(any(test, feature = "testing"), derive(test_strategy::Arbitrary))] +pub enum CurrentUpdateDisposition { + ConfigNotAvailable, + Known(OmicronSledUpdateDisposition), +} + +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, +)] +pub struct InstanceManagerStatus { + pub update_disposition: CurrentUpdateDisposition, + pub num_registered_vmms: usize, +} + +/// Identity and basic status information about this sled agent +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct Inventory { + pub sled_id: SledUuid, + pub sled_agent_address: SocketAddrV6, + pub sled_role: SledRole, + pub baseboard_id: BaseboardId, + pub usable_hardware_threads: u32, + pub usable_physical_ram: ByteCount, + pub cpu_family: SledCpuFamily, + pub reservoir_size: ByteCount, + pub disks: Vec, + pub zpools: Vec, + pub datasets: Vec, + pub ledgered_sled_config: Option, + pub reconciler_status: ConfigReconcilerInventoryStatus, + pub last_reconciliation: Option, + pub instance_manager_status: InstanceManagerStatus, + pub file_source_resolver: OmicronFileSourceResolverInventory, + pub smf_services_enabled_not_online: SvcsEnabledNotOnlineResult, + pub reference_measurements: IdOrdMap, + #[serde(with = "snake_case_result")] + #[schemars( + schema_with = "SnakeCaseResult::::json_schema" + )] + pub fmd: Result, +} + +impl From for crate::v51::inventory::Inventory { + fn from(value: Inventory) -> Self { + let Inventory { + sled_id, + sled_agent_address, + sled_role, + baseboard_id, + usable_hardware_threads, + usable_physical_ram, + cpu_family, + reservoir_size, + disks, + zpools, + datasets, + ledgered_sled_config, + reconciler_status, + last_reconciliation, + file_source_resolver, + smf_services_enabled_not_online, + reference_measurements, + fmd, + + // added in this version; drop it to downconvert + instance_manager_status: _, + } = value; + + crate::v51::inventory::Inventory { + sled_id, + sled_agent_address, + sled_role, + baseboard_id, + usable_hardware_threads, + usable_physical_ram, + cpu_family, + reservoir_size, + disks, + zpools, + datasets, + ledgered_sled_config, + reconciler_status, + last_reconciliation, + file_source_resolver, + smf_services_enabled_not_online, + reference_measurements, + fmd, + } + } +} diff --git a/sled-agent/types/versions/src/add_instance_manager_status_to_inventory/mod.rs b/sled-agent/types/versions/src/add_instance_manager_status_to_inventory/mod.rs new file mode 100644 index 00000000000..ddb6c2f5297 --- /dev/null +++ b/sled-agent/types/versions/src/add_instance_manager_status_to_inventory/mod.rs @@ -0,0 +1,13 @@ +// 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/. + +//! Version `ADD_INSTANCE_MANAGER_STATUS_TO_INVENTORY` of the Sled Agent API. +//! +//! This version adds the `instance_manager_status` field to inventory. This +//! field reports this sled's instance manager's count of registered VMMs and +//! the update disposition on which it's currently acting, providing an atomic +//! view that allows Reconfigurator to determine whether the sled has been fully +//! evacuated for update. + +pub mod inventory; diff --git a/sled-agent/types/versions/src/latest.rs b/sled-agent/types/versions/src/latest.rs index 7f4936b69b3..f963eddd316 100644 --- a/sled-agent/types/versions/src/latest.rs +++ b/sled-agent/types/versions/src/latest.rs @@ -203,7 +203,6 @@ pub mod inventory { pub use crate::v51::inventory::ConfigReconcilerInventory; pub use crate::v51::inventory::ConfigReconcilerInventoryStatus; pub use crate::v51::inventory::ExternalDnsAddrs; - pub use crate::v51::inventory::Inventory; pub use crate::v51::inventory::NexusExternalIps; pub use crate::v51::inventory::OmicronSledConfig; pub use crate::v51::inventory::OmicronZoneConfig; @@ -211,6 +210,10 @@ pub mod inventory { pub use crate::v51::inventory::OmicronZonesConfig; pub use crate::v51::inventory::ZoneSnatConfig; + pub use crate::v52::inventory::CurrentUpdateDisposition; + pub use crate::v52::inventory::InstanceManagerStatus; + pub use crate::v52::inventory::Inventory; + pub use crate::impls::inventory::FmdHostCaseDisplay; pub use crate::impls::inventory::FmdInventoryDisplay; pub use crate::impls::inventory::FmdInventoryResultDisplay; diff --git a/sled-agent/types/versions/src/lib.rs b/sled-agent/types/versions/src/lib.rs index d2947d657e9..ff85b233efd 100644 --- a/sled-agent/types/versions/src/lib.rs +++ b/sled-agent/types/versions/src/lib.rs @@ -107,6 +107,8 @@ pub mod v49; pub mod v50; #[path = "multiple_zone_external_ips/mod.rs"] pub mod v51; +#[path = "add_instance_manager_status_to_inventory/mod.rs"] +pub mod v52; #[path = "add_probe_put_endpoint/mod.rs"] pub mod v6; #[path = "multicast_support/mod.rs"]