Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 101 additions & 1 deletion nexus/reconfigurator/execution/src/datasets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub(crate) async fn deploy_datasets(
&log,
);

let config: DatasetsConfig = config.clone().into();
let config: DatasetsConfig = config.clone().into_in_service_datasets();
let result =
client.datasets_put(&config).await.with_context(
|| format!("Failed to put {config:#?} to sled {sled_id}"),
Expand Down Expand Up @@ -100,3 +100,103 @@ pub(crate) async fn deploy_datasets(
Err(errors)
}
}

#[cfg(test)]
mod tests {
use super::*;
use nexus_sled_agent_shared::inventory::SledRole;
use nexus_test_utils_macros::nexus_test;
use nexus_types::deployment::id_map::IdMap;
use nexus_types::deployment::BlueprintDatasetConfig;
use nexus_types::deployment::BlueprintDatasetDisposition;
use nexus_types::deployment::BlueprintDatasetsConfig;
use omicron_common::api::external::Generation;
use omicron_common::api::internal::shared::DatasetKind;
use omicron_common::disk::CompressionAlgorithm;
use omicron_common::zpool_name::ZpoolName;
use omicron_uuid_kinds::DatasetUuid;
use omicron_uuid_kinds::ZpoolUuid;
use std::net::SocketAddr;

type ControlPlaneTestContext =
nexus_test_utils::ControlPlaneTestContext<omicron_nexus::Server>;

#[nexus_test]
async fn test_deploy_datasets(cptestctx: &ControlPlaneTestContext) {
// Set up.
let nexus = &cptestctx.server.server_context().nexus;
let datastore = nexus.datastore();
let opctx = OpContext::for_tests(
cptestctx.logctx.log.clone(),
datastore.clone(),
);

let sim_sled_agent_addr = match cptestctx.sled_agents[0].local_addr() {
SocketAddr::V6(addr) => addr,
_ => panic!("Unexpected address type for sled agent (wanted IPv6)"),
};
let sim_sled_agent = &cptestctx.sled_agents[0].sled_agent();

// This is a fully fabricated dataset list for a simulated sled agent.
//
// We're testing the validity of the deployment calls here, not of any
// blueprint.

let sleds_by_id = BTreeMap::from([(
sim_sled_agent.id,
Sled::new(
sim_sled_agent.id,
sim_sled_agent_addr,
SledRole::Scrimlet,
),
)]);

// Create two datasets which look like they came from the blueprint: One
// which is in-service, and one which is expunged.
//
// During deployment, the in-service dataset should be deployed, but the
// expunged dataset should be ignored.
let dataset_id = DatasetUuid::new_v4();
let expunged_dataset_id = DatasetUuid::new_v4();
let mut datasets = IdMap::new();
datasets.insert(BlueprintDatasetConfig {
disposition: BlueprintDatasetDisposition::InService,
id: dataset_id,
pool: ZpoolName::new_external(ZpoolUuid::new_v4()),
kind: DatasetKind::Crucible,
address: None,
quota: None,
reservation: None,
compression: CompressionAlgorithm::Off,
});
datasets.insert(BlueprintDatasetConfig {
disposition: BlueprintDatasetDisposition::Expunged,
id: expunged_dataset_id,
pool: ZpoolName::new_external(ZpoolUuid::new_v4()),
kind: DatasetKind::Crucible,
address: None,
quota: None,
reservation: None,
compression: CompressionAlgorithm::Off,
});

let datasets_config =
BlueprintDatasetsConfig { generation: Generation::new(), datasets };
let sled_configs =
BTreeMap::from([(sim_sled_agent.id, datasets_config.clone())]);

// Give the simulated sled agent a configuration to deploy
deploy_datasets(&opctx, &sleds_by_id, &sled_configs)
.await
.expect("Deploying datasets should have succeeded");

// Observe the latest configuration stored on the simulated sled agent,
// and verify that this output matches the "deploy_datasets" input.
let observed_config = sim_sled_agent.datasets_config_list().unwrap();
assert_eq!(observed_config, datasets_config.into_in_service_datasets());

// We expect to see the single in-service dataset we supplied as input.
assert_eq!(observed_config.datasets.len(), 1,);
assert!(observed_config.datasets.contains_key(&dataset_id));
}
}
27 changes: 21 additions & 6 deletions nexus/types/src/deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,14 +949,29 @@ pub struct BlueprintDatasetsConfig {
pub datasets: IdMap<BlueprintDatasetConfig>,
}

impl From<BlueprintDatasetsConfig> for DatasetsConfig {
fn from(config: BlueprintDatasetsConfig) -> Self {
Self {
generation: config.generation,
datasets: config
impl BlueprintDatasetsConfig {
/// Converts [Self] into [DatasetsConfig].
///
/// [DatasetsConfig] is a format of the dataset configuration that can be
/// passed to Sled Agents for deployment.
///
/// This function is effectively a [std::convert::From] implementation, but
/// is named slightly more explicitly, as it filters the blueprint
/// configuration to only consider in-service datasets.
pub fn into_in_service_datasets(self) -> DatasetsConfig {
DatasetsConfig {
generation: self.generation,
datasets: self
.datasets
.into_iter()
.map(|d| (d.id, d.into()))
.filter_map(|d| {
if d.disposition.matches(BlueprintDatasetFilter::InService)
{
Some((d.id, d.into()))
} else {
None
}
})
.collect(),
}
}
Expand Down
Loading