Skip to content

Commit

Permalink
Expose disk firmware in inventory (#5706)
Browse files Browse the repository at this point in the history
The necessary bits to track a disk's firmware version over its lifetime.
This also plumbs up the firmware metadata to the inventory http
endpoint, although nothing is consuming it just yet as there will be a
follow up PR that actually inserts this data into CRDB.
  • Loading branch information
papertigers authored Jun 27, 2024
1 parent 28dc2ae commit 1e3e967
Show file tree
Hide file tree
Showing 14 changed files with 395 additions and 40 deletions.
26 changes: 23 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ key-manager = { path = "key-manager" }
kstat-rs = "0.2.4"
libc = "0.2.155"
libfalcon = { git = "https://github.com/oxidecomputer/falcon", rev = "e69694a1f7cc9fe31fab27f321017280531fb5f7" }
libnvme = { git = "https://github.com/oxidecomputer/libnvme", rev = "6fffcc81d2c423ed2d2e6c5c2827485554c4ecbe" }
libnvme = { git = "https://github.com/oxidecomputer/libnvme", rev = "dd5bb221d327a1bc9287961718c3c10d6bd37da0" }
linear-map = "1.2.0"
macaddr = { version = "1.0.1", features = ["serde_std"] }
maplit = "1.0.2"
Expand Down
2 changes: 1 addition & 1 deletion installinator/src/hardware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Hardware {
})?;

let disks: Vec<RawDisk> =
hardware.disks().into_iter().map(|disk| disk.into()).collect();
hardware.disks().into_values().map(|disk| disk.into()).collect();

info!(
log, "found gimlet hardware";
Expand Down
11 changes: 10 additions & 1 deletion sled-agent/src/hardware_monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ impl HardwareMonitor {
.detected_raw_disk_removal(disk.into())
.await;
}
HardwareUpdate::DiskUpdated(disk) => {
// We notify the storage manager of the hardware, but do not need to
// wait for the result to be fully processed.
#[allow(clippy::let_underscore_future)]
let _ = self
.storage_manager
.detected_raw_disk_update(disk.into())
.await;
}
},
Err(broadcast::error::RecvError::Lagged(count)) => {
warn!(self.log, "Hardware monitor missed {count} messages");
Expand Down Expand Up @@ -277,7 +286,7 @@ impl HardwareMonitor {
let _ = self
.storage_manager
.ensure_using_exactly_these_disks(
self.hardware_manager.disks().into_iter().map(RawDisk::from),
self.hardware_manager.disks().into_values().map(RawDisk::from),
)
.await;
}
Expand Down
2 changes: 1 addition & 1 deletion sled-agent/src/sled_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ impl SledAgent {
let mut disks = vec![];
let mut zpools = vec![];
let all_disks = self.storage().get_latest_disks().await;
for (identity, variant, slot) in all_disks.iter_all() {
for (identity, variant, slot, _firmware) in all_disks.iter_all() {
disks.push(crate::params::InventoryDisk {
identity: identity.clone(),
variant,
Expand Down
57 changes: 57 additions & 0 deletions sled-hardware/src/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,54 @@ impl DiskPaths {
}
}

#[derive(
Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Deserialize, Serialize,
)]
pub struct DiskFirmware {
active_slot: u8,
next_active_slot: Option<u8>,
slot1_read_only: bool,
// NB: This vec is 0 indexed while active_slot and next_active_slot are
// referring to "slots" in terms of the NVMe spec which defines slots 1-7.
// If the active_slot is 1, then it will be slot_firmware_versions[0] in the
// vector.
slot_firmware_versions: Vec<Option<String>>,
}

impl DiskFirmware {
pub fn active_slot(&self) -> u8 {
self.active_slot
}

pub fn next_active_slot(&self) -> Option<u8> {
self.next_active_slot
}

pub fn slot1_read_only(&self) -> bool {
self.slot1_read_only
}

pub fn slots(&self) -> &[Option<String>] {
self.slot_firmware_versions.as_slice()
}
}

impl DiskFirmware {
pub fn new(
active_slot: u8,
next_active_slot: Option<u8>,
slot1_read_only: bool,
slots: Vec<Option<String>>,
) -> Self {
Self {
active_slot,
next_active_slot,
slot1_read_only,
slot_firmware_versions: slots,
}
}
}

/// A disk which has been observed by monitoring hardware.
///
/// No guarantees are made about the partitions which exist within this disk.
Expand All @@ -147,6 +195,7 @@ pub struct UnparsedDisk {
variant: DiskVariant,
identity: DiskIdentity,
is_boot_disk: bool,
firmware: DiskFirmware,
}

impl UnparsedDisk {
Expand All @@ -157,13 +206,15 @@ impl UnparsedDisk {
variant: DiskVariant,
identity: DiskIdentity,
is_boot_disk: bool,
firmware: DiskFirmware,
) -> Self {
Self {
paths: DiskPaths { devfs_path, dev_path },
slot,
variant,
identity,
is_boot_disk,
firmware,
}
}

Expand All @@ -190,6 +241,10 @@ impl UnparsedDisk {
pub fn slot(&self) -> i64 {
self.slot
}

pub fn firmware(&self) -> &DiskFirmware {
&self.firmware
}
}

/// A physical disk that is partitioned to contain exactly one zpool
Expand All @@ -212,6 +267,7 @@ pub struct PooledDisk {
// This embeds the assumtion that there is exactly one parsed zpool per
// disk.
pub zpool_name: ZpoolName,
pub firmware: DiskFirmware,
}

impl PooledDisk {
Expand Down Expand Up @@ -252,6 +308,7 @@ impl PooledDisk {
is_boot_disk: unparsed_disk.is_boot_disk,
partitions,
zpool_name,
firmware: unparsed_disk.firmware,
})
}
}
Expand Down
Loading

0 comments on commit 1e3e967

Please sign in to comment.