Skip to content

Commit 05b8416

Browse files
committed
sled-agent: configure whether physical disks should be detected
1 parent 9927725 commit 05b8416

10 files changed

Lines changed: 124 additions & 86 deletions

File tree

dev-tools/xtask/src/virtual_hardware.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,8 +496,17 @@ fn get_gateway_mac(
496496
/// to parse these fields correctly.
497497
#[derive(Clone, Debug, Deserialize)]
498498
struct SledAgentConfig {
499-
/// Optional list of virtual devices to be used as "discovered disks".
500-
pub vdevs: Option<Vec<Utf8PathBuf>>,
499+
external_disks: SledAgentExternalDisks,
500+
}
501+
502+
#[derive(Clone, Debug, Deserialize)]
503+
#[serde(rename_all = "snake_case", tag = "kind")]
504+
enum SledAgentExternalDisks {
505+
Virtual {
506+
vdevs: Vec<Utf8PathBuf>,
507+
},
508+
#[serde(other)]
509+
Unknown,
501510
}
502511

503512
impl SledAgentConfig {
@@ -515,7 +524,8 @@ fn ensure_vdevs(
515524
) -> Result<()> {
516525
let config = SledAgentConfig::read(sled_agent_config)?;
517526

518-
let Some(vdevs) = &config.vdevs else {
527+
let SledAgentExternalDisks::Virtual { vdevs } = &config.external_disks
528+
else {
519529
bail!("No vdevs found in this configuration");
520530
};
521531

@@ -565,7 +575,7 @@ fn destroy_vdevs(
565575

566576
// Remove the vdev files themselves, if they are regular files
567577
let config = SledAgentConfig::read(sled_agent_config)?;
568-
if let Some(vdevs) = &config.vdevs {
578+
if let SledAgentExternalDisks::Virtual { vdevs } = &config.external_disks {
569579
for vdev in vdevs {
570580
let vdev_path = if vdev.is_absolute() {
571581
vdev.to_owned()

installinator/src/hardware.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use anyhow::Result;
77
use anyhow::anyhow;
88
use anyhow::ensure;
99
use omicron_common::disk::DiskVariant;
10+
use sled_hardware::ExternalDisks;
1011
use sled_hardware::HardwareManager;
1112
use sled_hardware::SledMode;
1213
use sled_storage::config::MountConfig;
@@ -25,10 +26,12 @@ impl Hardware {
2526
.context("failed to detect whether host is an oxide sled")?;
2627
ensure!(is_oxide_sled, "hardware scan only supported on oxide sleds");
2728

28-
let hardware = HardwareManager::new(log, SledMode::Auto, vec![])
29-
.map_err(|err| {
30-
anyhow!("failed to create HardwareManager: {err}")
31-
})?;
29+
let hardware = HardwareManager::new(
30+
log,
31+
SledMode::Auto,
32+
ExternalDisks::DetectPhysical,
33+
)
34+
.map_err(|err| anyhow!("failed to create HardwareManager: {err}"))?;
3235

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

sled-agent/src/config.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use illumos_utils::dladm::PhysicalLink;
1515
use omicron_common::vlan::VlanID;
1616
use serde::Deserialize;
1717
use sled_hardware::DataLinks;
18-
use sled_hardware::UnparsedDisk;
18+
use sled_hardware::ExternalDisks;
1919
use sprockets_tls::keys::SprocketsConfig;
2020

2121
#[derive(Clone, Debug, Deserialize)]
@@ -88,12 +88,8 @@ pub struct Config {
8888
pub swap_device_size_gb: Option<u32>,
8989
/// Optional VLAN ID to be used for tagging guest VNICs.
9090
pub vlan: Option<VlanID>,
91-
/// Optional list of virtual devices to be used as "discovered disks".
92-
pub vdevs: Option<Vec<Utf8PathBuf>>,
93-
/// Optional list of real devices to be injected as observed disks during
94-
/// device polling.
95-
#[serde(default)]
96-
pub nongimlet_observed_disks: Option<Vec<UnparsedDisk>>,
91+
/// The source of external disks to use.
92+
pub external_disks: ExternalDisks,
9793
/// Optionally skip waiting for time synchronization
9894
pub skip_timesync: Option<bool>,
9995

sled-agent/src/long_running_tasks.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use sled_agent_health_monitor::HealthMonitorHandle;
3535
use sled_agent_measurements::MeasurementsHandle;
3636
use sled_agent_resolvable_files::ZoneImageSourceResolver;
3737
use sled_agent_types::zone_bundle::CleanupContext;
38-
use sled_hardware::{HardwareManager, SledMode, UnparsedDisk};
38+
use sled_hardware::{ExternalDisks, HardwareManager, SledMode};
3939
use sled_storage::config::MountConfig;
4040
use sled_storage::disk::RawSyntheticDisk;
4141
use slog::{Logger, info};
@@ -125,11 +125,9 @@ pub async fn spawn_all_longrunning_tasks(
125125
log,
126126
);
127127

128-
let nongimlet_observed_disks =
129-
config.nongimlet_observed_disks.clone().unwrap_or(vec![]);
130-
131128
let hardware_manager =
132-
spawn_hardware_manager(log, sled_mode, nongimlet_observed_disks).await;
129+
spawn_hardware_manager(log, sled_mode, config.external_disks.clone())
130+
.await;
133131

134132
// Start monitoring for hardware changes, adding some synthetic disks if
135133
// necessary.
@@ -231,7 +229,7 @@ fn spawn_key_manager(
231229
async fn spawn_hardware_manager(
232230
log: &Logger,
233231
sled_mode: SledMode,
234-
nongimlet_observed_disks: Vec<UnparsedDisk>,
232+
external_disks: ExternalDisks,
235233
) -> HardwareManager {
236234
// The `HardwareManager` does not use the the "task/handle" pattern
237235
// and spawns its worker task inside `HardwareManager::new`. Instead of returning
@@ -241,10 +239,10 @@ async fn spawn_hardware_manager(
241239
//
242240
// There are pros and cons to both methods, but the reason to mention it here is that
243241
// the handle in this case is the `HardwareManager` itself.
244-
info!(log, "Starting HardwareManager"; "sled_mode" => ?sled_mode, "nongimlet_observed_disks" => ?nongimlet_observed_disks);
242+
info!(log, "Starting HardwareManager"; "sled_mode" => ?sled_mode, "external_disks" => ?external_disks);
245243
let log = log.clone();
246244
tokio::task::spawn_blocking(move || {
247-
HardwareManager::new(&log, sled_mode, nongimlet_observed_disks).unwrap()
245+
HardwareManager::new(&log, sled_mode, external_disks).unwrap()
248246
})
249247
.await
250248
.unwrap()
@@ -363,7 +361,7 @@ async fn upsert_synthetic_disks_if_needed(
363361
raw_disks_tx: &RawDisksSender,
364362
config: &Config,
365363
) {
366-
if let Some(vdevs) = &config.vdevs {
364+
if let ExternalDisks::Virtual { vdevs } = &config.external_disks {
367365
for (i, vdev) in vdevs.iter().enumerate() {
368366
info!(
369367
log,

sled-hardware/src/illumos/mod.rs

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

55
use crate::DiskFirmware;
6+
use crate::ExternalDisks;
67
use crate::HardwareView;
78
use crate::TofinoSnapshot;
89
use crate::TofinoView;
@@ -124,7 +125,10 @@ struct HardwareSnapshot {
124125

125126
impl HardwareSnapshot {
126127
// Walk the device tree to capture a view of the current hardware.
127-
fn new(log: &Logger) -> Result<Self, Error> {
128+
fn new(
129+
log: &Logger,
130+
external_disks: &ExternalDisks,
131+
) -> Result<Self, Error> {
128132
let mut device_info =
129133
DevInfo::new_force_load().map_err(Error::DevInfo)?;
130134

@@ -168,17 +172,27 @@ impl HardwareSnapshot {
168172

169173
// Monitor for block devices.
170174
let mut disks = HashMap::new();
171-
let mut node_walker = device_info.walk_driver("blkdev");
172-
while let Some(node) =
173-
node_walker.next().transpose().map_err(Error::DevInfo)?
174-
{
175-
poll_blkdev_node(
176-
&log,
177-
sled_type,
178-
&mut disks,
179-
node,
180-
boot_storage_unit,
181-
)?;
175+
match external_disks {
176+
ExternalDisks::DetectPhysical => {
177+
let mut node_walker = device_info.walk_driver("blkdev");
178+
while let Some(node) =
179+
node_walker.next().transpose().map_err(Error::DevInfo)?
180+
{
181+
poll_blkdev_node(
182+
&log,
183+
sled_type,
184+
&mut disks,
185+
node,
186+
boot_storage_unit,
187+
)?;
188+
}
189+
}
190+
ExternalDisks::HardcodedPhysical { disks: hardcoded_disks } => {
191+
for disk in hardcoded_disks {
192+
disks.insert(disk.identity().clone(), disk.clone());
193+
}
194+
}
195+
ExternalDisks::Virtual { .. } => {}
182196
}
183197

184198
Ok(Self { tofino, disks, baseboard })
@@ -504,10 +518,10 @@ fn poll_blkdev_node(
504518
fn poll_device_tree(
505519
log: &Logger,
506520
hardware_view_tx: &watch::Sender<HardwareView>,
507-
nonsled_observed_disks: &[UnparsedDisk],
521+
external_disks: &ExternalDisks,
508522
) -> Result<(), Error> {
509523
// Construct a view of hardware by walking the device tree.
510-
let polled_hw = match HardwareSnapshot::new(log) {
524+
let polled_hw = match HardwareSnapshot::new(log, external_disks) {
511525
Ok(polled_hw) => polled_hw,
512526

513527
Err(e) => {
@@ -529,16 +543,19 @@ fn poll_device_tree(
529543

530544
// For platforms that don't support the HardwareSnapshot
531545
// functionality, sled-agent can be supplied a fixed list of
532-
// UnparsedDisks. Add those to the HardwareSnapshot here if they
533-
// are missing (which they will be for non-sleds).
534-
for observed_disk in nonsled_observed_disks {
535-
let identity = observed_disk.identity();
536-
if !inner.disks.contains_key(identity) {
537-
inner.disks.insert(
538-
identity.clone(),
539-
observed_disk.clone(),
540-
);
541-
did_modify = true;
546+
// UnparsedDisks. Add those to the HardwareSnapshot here if
547+
// they are missing (which they will be for non-sleds).
548+
if let ExternalDisks::HardcodedPhysical { disks } =
549+
external_disks
550+
{
551+
for disk in disks {
552+
let identity = disk.identity();
553+
if !inner.disks.contains_key(identity) {
554+
inner
555+
.disks
556+
.insert(identity.clone(), disk.clone());
557+
did_modify = true;
558+
}
542559
}
543560
}
544561

@@ -747,11 +764,10 @@ fn parse_smbios_output(log: &Logger, output: String) -> Option<Baseboard> {
747764
fn hardware_tracking_task(
748765
log: Logger,
749766
hardware_view_tx: watch::Sender<HardwareView>,
750-
nonsled_observed_disks: Vec<UnparsedDisk>,
767+
external_disks: ExternalDisks,
751768
) {
752769
loop {
753-
match poll_device_tree(&log, &hardware_view_tx, &nonsled_observed_disks)
754-
{
770+
match poll_device_tree(&log, &hardware_view_tx, &external_disks) {
755771
// We've already warned about `NotAnOxideSled` by this point,
756772
// so let's not spam the logs.
757773
Ok(_) | Err(Error::NotAnOxideSled(_)) => (),
@@ -785,7 +801,7 @@ impl HardwareManager {
785801
pub fn new(
786802
log: &Logger,
787803
sled_mode: SledMode,
788-
nonsled_observed_disks: Vec<UnparsedDisk>,
804+
external_disks: ExternalDisks,
789805
) -> Result<Self, String> {
790806
let log = log.new(o!("component" => "HardwareManager"));
791807
info!(log, "Creating HardwareManager");
@@ -837,8 +853,7 @@ impl HardwareManager {
837853
// This mitigates issues where the Sled Agent could try to propagate
838854
// an "empty" view of hardware to other consumers before the first
839855
// query.
840-
match poll_device_tree(&log, &hardware_view_tx, &nonsled_observed_disks)
841-
{
856+
match poll_device_tree(&log, &hardware_view_tx, &external_disks) {
842857
Ok(_) => (),
843858
// Allow non-sled devices to proceed with a "null" view of
844859
// hardware, otherwise they won't be able to start.
@@ -865,11 +880,7 @@ impl HardwareManager {
865880
});
866881

867882
std::thread::spawn(move || {
868-
hardware_tracking_task(
869-
log,
870-
hardware_view_tx,
871-
nonsled_observed_disks,
872-
);
883+
hardware_tracking_task(log, hardware_view_tx, external_disks);
873884
});
874885

875886
Ok(Self { hardware_view_rx })

sled-hardware/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ pub enum DataLinks {
6565
Physical,
6666
}
6767

68+
#[derive(Clone, Debug, Serialize, Deserialize)]
69+
#[serde(rename_all = "snake_case", tag = "kind")]
70+
pub enum ExternalDisks {
71+
/// Instead of detecting physical disks, use the provided file-backed vdevs.
72+
Virtual { vdevs: Vec<String> },
73+
/// Instead of detecting physical disks, inject the provided ones during
74+
/// device polling.
75+
HardcodedPhysical { disks: Vec<UnparsedDisk> },
76+
/// Detect physical external disks connected to the sled.
77+
DetectPhysical,
78+
}
79+
6880
/// Configuration for forcing a sled to run as a Scrimlet or compute Sled
6981
#[derive(Copy, Clone, Debug)]
7082
pub enum SledMode {

sled-hardware/src/non_illumos/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use std::collections::HashMap;
66

77
use crate::disk::{DiskPaths, Partition, PooledDiskError, UnparsedDisk};
8-
use crate::{HardwareView, SledMode};
8+
use crate::{ExternalDisks, HardwareView, SledMode};
99
use omicron_common::disk::{DiskIdentity, DiskVariant};
1010
use omicron_uuid_kinds::ZpoolUuid;
1111
use sled_hardware_types::{Baseboard, SledCpuFamily};
@@ -33,7 +33,7 @@ impl HardwareManager {
3333
pub fn new(
3434
_log: &Logger,
3535
_sled_mode: SledMode,
36-
_nonsled_observed_disks: Vec<UnparsedDisk>,
36+
_external_disks: ExternalDisks,
3737
) -> Result<Self, String> {
3838
unimplemented!("Accessing hardware unsupported on non-illumos");
3939
}

smf/sled-agent/gimlet-standalone/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ swap_device_size_gb = 256
6363
# $ dladm show-phys -p -o LINK
6464
# data_link = "igb0"
6565

66+
[external_disks]
67+
kind = "detect_physical"
68+
6669
[data_links]
6770
kind = "virtual"
6871
devices = ["net0", "net1"]

smf/sled-agent/gimlet/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ vmm_reservoir_percentage = 86.3
5959
# allocated.
6060
swap_device_size_gb = 256
6161

62+
[external_disks]
63+
kind = "detect_physical"
64+
6265
[data_links]
6366
kind = "physical"
6467

0 commit comments

Comments
 (0)