Skip to content

Commit

Permalink
[2/n] [reconfigurator] handle empty zones/disks use cases within Exam…
Browse files Browse the repository at this point in the history
…pleSystem (#6768)

Currently, we build example systems and then mutate the inputs in various ways,
usually to empty out zones and disks.

With this PR, more of these cases are handled within the example system
via a builder pattern. This simplifies upcoming work to improve
`ExampleSystem` instances for more robust tests.

This also makes a change to `ExampleSystem` to not carry around the
blueprint -- logically, the blueprint evolves separately from the
underlying system. This change also simplifies some upcoming work around
making the collection and input behave correctly.
  • Loading branch information
sunshowers authored Oct 4, 2024
1 parent 8e5ef40 commit 13d411f
Show file tree
Hide file tree
Showing 9 changed files with 270 additions and 177 deletions.
2 changes: 1 addition & 1 deletion nexus/db-queries/src/db/datastore/deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1869,7 +1869,7 @@ mod tests {
) -> (Collection, PlanningInput, Blueprint) {
// We'll start with an example system.
let (mut base_collection, planning_input, mut blueprint) =
example(log, test_name, 3);
example(log, test_name);

// Take a more thorough collection representative (includes SPs,
// etc.)...
Expand Down
6 changes: 4 additions & 2 deletions nexus/reconfigurator/execution/src/datasets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ pub(crate) async fn ensure_dataset_records_exist(
mod tests {
use super::*;
use nexus_db_model::Zpool;
use nexus_reconfigurator_planning::example::example;
use nexus_reconfigurator_planning::example::ExampleSystemBuilder;
use nexus_sled_agent_shared::inventory::OmicronZoneDataset;
use nexus_test_utils_macros::nexus_test;
use nexus_types::deployment::blueprint_zone_type;
Expand Down Expand Up @@ -149,7 +149,9 @@ mod tests {
let opctx = &opctx;

// Use the standard example system.
let (collection, _, blueprint) = example(&opctx.log, TEST_NAME, 5);
let (example, blueprint) =
ExampleSystemBuilder::new(&opctx.log, TEST_NAME).nsleds(5).build();
let collection = example.collection;

// Record the sleds and zpools.
crate::tests::insert_sled_records(datastore, &blueprint).await;
Expand Down
5 changes: 3 additions & 2 deletions nexus/reconfigurator/execution/src/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ mod test {
use nexus_inventory::CollectionBuilder;
use nexus_reconfigurator_planning::blueprint_builder::BlueprintBuilder;
use nexus_reconfigurator_planning::blueprint_builder::EnsureMultiple;
use nexus_reconfigurator_planning::example::example;
use nexus_reconfigurator_planning::example::ExampleSystemBuilder;
use nexus_reconfigurator_preparation::PlanningInputFromDb;
use nexus_sled_agent_shared::inventory::OmicronZoneConfig;
use nexus_sled_agent_shared::inventory::OmicronZoneType;
Expand Down Expand Up @@ -1138,7 +1138,8 @@ mod test {
async fn test_blueprint_external_dns_basic() {
static TEST_NAME: &str = "test_blueprint_external_dns_basic";
let logctx = test_setup_log(TEST_NAME);
let (_, _, mut blueprint) = example(&logctx.log, TEST_NAME, 5);
let (_, mut blueprint) =
ExampleSystemBuilder::new(&logctx.log, TEST_NAME).nsleds(5).build();
blueprint.internal_dns_version = Generation::new();
blueprint.external_dns_version = Generation::new();

Expand Down
131 changes: 61 additions & 70 deletions nexus/reconfigurator/planning/src/blueprint_builder/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1928,7 +1928,7 @@ impl<'a> BlueprintDisksBuilder<'a> {
pub mod test {
use super::*;
use crate::example::example;
use crate::example::ExampleSystem;
use crate::example::ExampleSystemBuilder;
use crate::system::SledBuilder;
use expectorate::assert_contents;
use nexus_inventory::CollectionBuilder;
Expand All @@ -1942,8 +1942,6 @@ pub mod test {
use std::collections::BTreeSet;
use std::mem;

pub const DEFAULT_N_SLEDS: usize = 3;

/// Checks various conditions that should be true for all blueprints
#[track_caller]
pub fn verify_blueprint(blueprint: &Blueprint) {
Expand Down Expand Up @@ -2033,7 +2031,7 @@ pub mod test {
static TEST_NAME: &str = "blueprint_builder_test_initial";
let logctx = test_setup_log(TEST_NAME);
let (collection, input, blueprint_initial) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
example(&logctx.log, TEST_NAME);
verify_blueprint(&blueprint_initial);

let diff = blueprint_initial.diff_since_collection(&collection);
Expand Down Expand Up @@ -2068,14 +2066,13 @@ pub mod test {
fn test_basic() {
static TEST_NAME: &str = "blueprint_builder_test_basic";
let logctx = test_setup_log(TEST_NAME);
let mut example =
ExampleSystem::new(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
let blueprint1 = &example.blueprint;
verify_blueprint(blueprint1);
let (mut example, blueprint1) =
ExampleSystemBuilder::new(&logctx.log, TEST_NAME).build();
verify_blueprint(&blueprint1);

let mut builder = BlueprintBuilder::new_based_on(
&logctx.log,
blueprint1,
&blueprint1,
&example.input,
&example.collection,
"test_basic",
Expand Down Expand Up @@ -2227,7 +2224,7 @@ pub mod test {
"blueprint_builder_test_prune_decommissioned_sleds";
let logctx = test_setup_log(TEST_NAME);
let (collection, input, mut blueprint1) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
example(&logctx.log, TEST_NAME);
verify_blueprint(&blueprint1);

// Mark one sled as having a desired state of decommissioned.
Expand Down Expand Up @@ -2312,23 +2309,16 @@ pub mod test {
fn test_add_physical_disks() {
static TEST_NAME: &str = "blueprint_builder_test_add_physical_disks";
let logctx = test_setup_log(TEST_NAME);
let (collection, input, _) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
let input = {
// Clear out the external networking records from `input`, since
// we're building an empty blueprint.
let mut builder = input.into_builder();
*builder.network_resources_mut() =
OmicronZoneNetworkResources::new();
builder.build()
};

// Start with an empty blueprint (sleds with no zones).
let parent = BlueprintBuilder::build_empty_with_sleds_seeded(
input.all_sled_ids(SledFilter::Commissioned),
"test",
TEST_NAME,
);
// Start with an empty system (sleds with no zones). However, we leave
// the disks around so that `sled_ensure_disks` can add them.
let (example, parent) =
ExampleSystemBuilder::new(&logctx.log, TEST_NAME)
.create_zones(false)
.create_disks_in_blueprint(false)
.build();
let collection = example.collection;
let input = example.input;

{
// We start empty, and can add a disk
Expand All @@ -2342,7 +2332,17 @@ pub mod test {
.expect("failed to create builder");

assert!(builder.disks.changed_disks.is_empty());
assert!(builder.disks.parent_disks.is_empty());
// In the parent_disks map, we expect entries to be present for
// each sled, but not have any disks in them.
for (sled_id, disks) in builder.disks.parent_disks {
assert_eq!(
disks.disks,
Vec::new(),
"for sled {}, expected no disks present in parent, \
but found some",
sled_id
);
}

for (sled_id, sled_resources) in
input.all_sled_resources(SledFilter::InService)
Expand All @@ -2351,12 +2351,25 @@ pub mod test {
builder
.sled_ensure_disks(sled_id, &sled_resources)
.unwrap(),
EnsureMultiple::Changed { added: 10, removed: 0 },
EnsureMultiple::Changed {
added: usize::from(SledBuilder::DEFAULT_NPOOLS),
removed: 0
},
);
}

assert!(!builder.disks.changed_disks.is_empty());
assert!(builder.disks.parent_disks.is_empty());
// In the parent_disks map, we expect entries to be present for
// each sled, but not have any disks in them.
for (sled_id, disks) in builder.disks.parent_disks {
assert_eq!(
disks.disks,
Vec::new(),
"for sled {}, expected no disks present in parent, \
but found some",
sled_id
);
}
}

logctx.cleanup_successful();
Expand All @@ -2368,8 +2381,7 @@ pub mod test {
static TEST_NAME: &str =
"blueprint_builder_test_zone_filesystem_zpool_colocated";
let logctx = test_setup_log(TEST_NAME);
let (_, _, blueprint) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
let (_, _, blueprint) = example(&logctx.log, TEST_NAME);

for (_, zone_config) in &blueprint.blueprint_zones {
for zone in &zone_config.zones {
Expand All @@ -2393,22 +2405,13 @@ pub mod test {
"blueprint_builder_test_add_nexus_with_no_existing_nexus_zones";
let logctx = test_setup_log(TEST_NAME);

// Discard the example blueprint and start with an empty one.
let (collection, input, _) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
let input = {
// Clear out the external networking records from `input`, since
// we're building an empty blueprint.
let mut builder = input.into_builder();
*builder.network_resources_mut() =
OmicronZoneNetworkResources::new();
builder.build()
};
let parent = BlueprintBuilder::build_empty_with_sleds_seeded(
input.all_sled_ids(SledFilter::Commissioned),
"test",
TEST_NAME,
);
// Start with an empty system (sleds with no zones).
let (example, parent) =
ExampleSystemBuilder::new(&logctx.log, TEST_NAME)
.create_zones(false)
.build();
let collection = example.collection;
let input = example.input;

// Adding a new Nexus zone currently requires copying settings from an
// existing Nexus zone. `parent` has no zones, so we should fail if we
Expand Down Expand Up @@ -2447,7 +2450,7 @@ pub mod test {
static TEST_NAME: &str = "blueprint_builder_test_add_nexus_error_cases";
let logctx = test_setup_log(TEST_NAME);
let (mut collection, mut input, mut parent) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
example(&logctx.log, TEST_NAME);

// Remove the Nexus zone from one of the sleds so that
// `sled_ensure_zone_nexus` can attempt to add a Nexus zone to
Expand Down Expand Up @@ -2602,8 +2605,7 @@ pub mod test {
"blueprint_builder_test_invalid_parent_blueprint_\
two_zones_with_same_external_ip";
let logctx = test_setup_log(TEST_NAME);
let (collection, input, mut parent) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
let (collection, input, mut parent) = example(&logctx.log, TEST_NAME);

// We should fail if the parent blueprint claims to contain two
// zones with the same external IP. Skim through the zones, copy the
Expand Down Expand Up @@ -2661,8 +2663,7 @@ pub mod test {
"blueprint_builder_test_invalid_parent_blueprint_\
two_nexus_zones_with_same_nic_ip";
let logctx = test_setup_log(TEST_NAME);
let (collection, input, mut parent) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
let (collection, input, mut parent) = example(&logctx.log, TEST_NAME);

// We should fail if the parent blueprint claims to contain two
// Nexus zones with the same NIC IP. Skim through the zones, copy
Expand Down Expand Up @@ -2720,8 +2721,7 @@ pub mod test {
"blueprint_builder_test_invalid_parent_blueprint_\
two_zones_with_same_vnic_mac";
let logctx = test_setup_log(TEST_NAME);
let (collection, input, mut parent) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
let (collection, input, mut parent) = example(&logctx.log, TEST_NAME);

// We should fail if the parent blueprint claims to contain two
// zones with the same service vNIC MAC address. Skim through the
Expand Down Expand Up @@ -2778,22 +2778,13 @@ pub mod test {
static TEST_NAME: &str = "blueprint_builder_test_ensure_cockroachdb";
let logctx = test_setup_log(TEST_NAME);

// Discard the example blueprint and start with an empty one.
let (collection, input, _) =
example(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
let input = {
// Clear out the external networking records from `input`, since
// we're building an empty blueprint.
let mut builder = input.into_builder();
*builder.network_resources_mut() =
OmicronZoneNetworkResources::new();
builder.build()
};
let parent = BlueprintBuilder::build_empty_with_sleds_seeded(
input.all_sled_ids(SledFilter::Commissioned),
"test",
TEST_NAME,
);
// Start with an empty system (sleds with no zones).
let (example, parent) =
ExampleSystemBuilder::new(&logctx.log, TEST_NAME)
.create_zones(false)
.build();
let collection = example.collection;
let input = example.input;

// Pick an arbitrary sled.
let (target_sled_id, sled_resources) = input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl DnsSubnetAllocator {
pub mod test {
use super::*;
use crate::blueprint_builder::test::verify_blueprint;
use crate::example::ExampleSystem;
use crate::example::ExampleSystemBuilder;
use nexus_types::deployment::BlueprintZoneFilter;
use omicron_common::policy::INTERNAL_DNS_REDUNDANCY;
use omicron_test_utils::dev::test_setup_log;
Expand All @@ -115,9 +115,10 @@ pub mod test {
assert!(INTERNAL_DNS_REDUNDANCY > 1);

// Use our example system to create a blueprint and input.
let mut example =
ExampleSystem::new(&logctx.log, TEST_NAME, INTERNAL_DNS_REDUNDANCY);
let blueprint1 = &mut example.blueprint;
let (example, mut blueprint1) =
ExampleSystemBuilder::new(&logctx.log, TEST_NAME)
.nsleds(INTERNAL_DNS_REDUNDANCY)
.build();

// `ExampleSystem` adds an internal DNS server to every sled. Manually
// prune out all but the first of them to give us space to add more.
Expand All @@ -127,7 +128,7 @@ pub mod test {
let npruned = blueprint1.blueprint_zones.len() - 1;
assert!(npruned > 0);

verify_blueprint(blueprint1);
verify_blueprint(&blueprint1);

// Create an allocator.
let mut allocator = DnsSubnetAllocator::new(
Expand Down
12 changes: 4 additions & 8 deletions nexus/reconfigurator/planning/src/blueprint_builder/zones.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,8 @@ mod tests {
use omicron_uuid_kinds::ZpoolUuid;

use crate::{
blueprint_builder::{
test::{verify_blueprint, DEFAULT_N_SLEDS},
BlueprintBuilder, Ensure,
},
example::ExampleSystem,
blueprint_builder::{test::verify_blueprint, BlueprintBuilder, Ensure},
example::ExampleSystemBuilder,
};

use super::*;
Expand All @@ -255,9 +252,8 @@ mod tests {
fn test_builder_zones() {
static TEST_NAME: &str = "blueprint_test_builder_zones";
let logctx = test_setup_log(TEST_NAME);
let mut example =
ExampleSystem::new(&logctx.log, TEST_NAME, DEFAULT_N_SLEDS);
let blueprint_initial = example.blueprint;
let (mut example, blueprint_initial) =
ExampleSystemBuilder::new(&logctx.log, TEST_NAME).build();

// Add a completely bare sled to the input.
let (new_sled_id, input2) = {
Expand Down
Loading

0 comments on commit 13d411f

Please sign in to comment.