Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewjstone committed Sep 29, 2023
1 parent ab57c46 commit 90ec972
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 4 deletions.
129 changes: 125 additions & 4 deletions sled-storage/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use std::collections::{BTreeSet, HashSet};

use crate::dataset::DatasetError;
use crate::dataset::{self, DatasetError};
use crate::disk::{Disk, DiskError, DiskWrapper};
use crate::error::Error;
use crate::resources::StorageResources;
Expand Down Expand Up @@ -46,7 +46,7 @@ pub struct StorageManager {
rx: mpsc::Receiver<StorageRequest>,
resources: StorageResources,
queued_u2_drives: HashSet<UnparsedDisk>,
queued_synthetic_u2_drives: BTreeSet<ZpoolName>,
queued_synthetic_u2_drives: HashSet<ZpoolName>,
key_requester: StorageKeyRequester,
}

Expand All @@ -63,14 +63,14 @@ impl StorageManager {
rx,
resources: StorageResources::default(),
queued_u2_drives: HashSet::new(),
queued_synthetic_u2_drives: BTreeSet::new(),
queued_synthetic_u2_drives: HashSet::new(),
key_requester,
},
StorageHandle { tx },
)
}

/// Add a disk to storage resources or queue it to be added later
/// Add a real U.2 disk to storage resources or queue it to be added later
async fn add_u2_disk(
&mut self,
unparsed_disk: UnparsedDisk,
Expand Down Expand Up @@ -107,4 +107,125 @@ impl StorageManager {
}
}
}

/// Add a synthetic U.2 disk to storage resources or queue it to be added later
async fn add_synthetic_u2_disk(
&mut self,
zpool_name: ZpoolName,
) -> Result<(), Error> {
if self.stage != StorageManagerStage::Normal {
self.queued_synthetic_u2_drives.insert(zpool_name);
return Ok(());
}

let synthetic_id = DiskIdentity {
vendor: "fake_vendor".to_string(),
serial: "fake_serial".to_string(),
model: zpool_name.id().to_string(),
};
match dataset::ensure_zpool_has_datasets(
&self.log,
&zpool_name,
&synthetic_id,
Some(&self.key_requester),
)
.await
{
Ok(disk) => self.resources.insert_synthetic_disk(zpool_name),
Err(err @ DatasetError::KeyManager(_)) => {
warn!(
self.log,
"Transient error: {err} - queuing disk {:?}", synthetic_id
);
self.queued_synthetic_u2_drives.insert(zpool_name);
self.stage = StorageManagerStage::QueuingDisks;
Err(DiskError::Dataset(err).into())
}
Err(err) => {
error!(
self.log,
"Persistent error: {err} - not queueing disk {:?}",
synthetic_id
);
Err(DiskError::Dataset(err).into())
}
}
}
}

/// All tests only use synthetic disks, but are expected to be run on illumos
/// systems.
#[cfg(all(test, target_os = "illumos"))]
mod tests {
use super::*;
use async_trait::async_trait;
use key_manager::{
KeyManager, SecretRetriever, SecretRetrieverError, SecretState,
VersionedIkm,
};
use uuid::Uuid;

pub fn log() -> slog::Logger {
let drain = slog::Discard;
slog::Logger::root(drain, o!())
}

/// A [`key-manager::SecretRetriever`] that only returns hardcoded IKM for
/// epoch 0
#[derive(Debug)]
struct HardcodedSecretRetriever {}

#[async_trait]
impl SecretRetriever for HardcodedSecretRetriever {
async fn get_latest(
&self,
) -> Result<VersionedIkm, SecretRetrieverError> {
let epoch = 0;
let salt = [0u8; 32];
let secret = [0x1d; 32];

Ok(VersionedIkm::new(epoch, salt, &secret))
}

/// We don't plan to do any key rotation before trust quorum is ready
async fn get(
&self,
epoch: u64,
) -> Result<SecretState, SecretRetrieverError> {
if epoch != 0 {
return Err(SecretRetrieverError::NoSuchEpoch(epoch));
}
Ok(SecretState::Current(self.get_latest().await?))
}
}

#[tokio::test]
async fn add_u2_disk_while_not_in_normal_stage_and_ensure_it_gets_queued() {
let (mut _key_manager, key_requester) =
KeyManager::new(&log(), HardcodedSecretRetriever {});
let (mut manager, _) = StorageManager::new(&log(), key_requester);
let zpool_name = ZpoolName::new_external(Uuid::new_v4());
assert_eq!(StorageManagerStage::WaitingForBootDisk, manager.stage);
manager.add_synthetic_u2_disk(zpool_name.clone()).await.unwrap();
assert!(manager.resources.all_u2_zpools().is_empty());
assert_eq!(
manager.queued_synthetic_u2_drives,
HashSet::from([zpool_name.clone()])
);

// Walk through other non-normal stages and enusre disk gets queued
for stage in [
StorageManagerStage::WaitingForKeyManager,
StorageManagerStage::QueuingDisks,
] {
manager.queued_synthetic_u2_drives.clear();
manager.stage = stage;
manager.add_synthetic_u2_disk(zpool_name.clone()).await.unwrap();
assert!(manager.resources.all_u2_zpools().is_empty());
assert_eq!(
manager.queued_synthetic_u2_drives,
HashSet::from([zpool_name.clone()])
);
}
}
}
13 changes: 13 additions & 0 deletions sled-storage/src/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@ impl StorageResources {
Ok(())
}

/// Insert a synthetic disk and its zpool
pub(crate) fn insert_synthetic_disk(
&mut self,
zpool_name: ZpoolName,
) -> Result<(), Error> {
let disk = DiskWrapper::Synthetic { zpool_name: zpool_name.clone() };
let parent = disk.identity().clone();
Arc::make_mut(&mut self.disks).insert(disk.identity(), disk);
let zpool = Pool::new(zpool_name, parent)?;
Arc::make_mut(&mut self.pools).insert(zpool.name.id(), zpool);
Ok(())
}

/// Returns the identity of the boot disk.
///
/// If this returns `None`, we have not processed the boot disk yet.
Expand Down

0 comments on commit 90ec972

Please sign in to comment.