Skip to content

Commit 84e9c27

Browse files
authored
Remove ability to generate a Blueprint from an inventory collection (#5583)
We want to add information in blueprints, particularly `BlueprintZoneConfig` and `BlueprintZoneType`, that is not present in the sled-agent types `OmicronZoneConfig` and `OmicronZoneType`. Today on main conversion between those types is bidirectional. As we add to blueprints, we will continue to be able to convert a `BlueprintZoneConfig` into an `OmicronZoneConfig`, but the opposite direction will become more and more difficult as callers need to provide the additional information required for blueprints. We have enough users of the inventory -> blueprint direction that it's quite painful to try to add to blueprints, so this PR attempts to knock out one of the more common uses: converting an inventory collection into a blueprint via `BlueprintBuilder::build_initial_from_collection()`. This method is removed, and all the remaining changes are fallout from that. Most uses of this have been replaced by either the blueprint produced by `ExampleSystem` or the new `BlueprintBuilder::build_empty_with_sleds()` helper for constructing an empty blueprint. One test needed the full blueprint-from-inventory, so that one actually gained a new use of converting OmicronZoneConfig -> BlueprintZoneConfig. (Not ideal, but fine for now!)
1 parent a080dff commit 84e9c27

File tree

16 files changed

+448
-906
lines changed

16 files changed

+448
-906
lines changed

dev-tools/omdb/src/bin/omdb/nexus.rs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@ enum BlueprintsCommands {
9797
Delete(BlueprintIdArgs),
9898
/// Interact with the current target blueprint
9999
Target(BlueprintsTargetArgs),
100-
/// Generate an initial blueprint from a specific inventory collection
101-
GenerateFromCollection(CollectionIdArgs),
102100
/// Generate a new blueprint
103101
Regenerate,
104102
/// Import a blueprint
@@ -361,15 +359,6 @@ impl NexusArgs {
361359
let token = omdb.check_allow_destructive()?;
362360
cmd_nexus_blueprints_regenerate(&client, token).await
363361
}
364-
NexusCommands::Blueprints(BlueprintsArgs {
365-
command: BlueprintsCommands::GenerateFromCollection(args),
366-
}) => {
367-
let token = omdb.check_allow_destructive()?;
368-
cmd_nexus_blueprints_generate_from_collection(
369-
&client, args, token,
370-
)
371-
.await
372-
}
373362
NexusCommands::Blueprints(BlueprintsArgs {
374363
command: BlueprintsCommands::Import(args),
375364
}) => {
@@ -1134,26 +1123,6 @@ async fn cmd_nexus_blueprints_target_set_enabled(
11341123
Ok(())
11351124
}
11361125

1137-
async fn cmd_nexus_blueprints_generate_from_collection(
1138-
client: &nexus_client::Client,
1139-
args: &CollectionIdArgs,
1140-
_destruction_token: DestructiveOperationToken,
1141-
) -> Result<(), anyhow::Error> {
1142-
let blueprint = client
1143-
.blueprint_generate_from_collection(
1144-
&nexus_client::types::CollectionId {
1145-
collection_id: args.collection_id,
1146-
},
1147-
)
1148-
.await
1149-
.context("creating blueprint from collection id")?;
1150-
eprintln!(
1151-
"created blueprint {} from collection id {}",
1152-
blueprint.id, args.collection_id
1153-
);
1154-
Ok(())
1155-
}
1156-
11571126
async fn cmd_nexus_blueprints_regenerate(
11581127
client: &nexus_client::Client,
11591128
_destruction_token: DestructiveOperationToken,

dev-tools/reconfigurator-cli/src/main.rs

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,6 @@ fn process_entry(sim: &mut ReconfiguratorSim, entry: String) -> LoopResult {
314314
Commands::InventoryList => cmd_inventory_list(sim),
315315
Commands::InventoryGenerate => cmd_inventory_generate(sim),
316316
Commands::BlueprintList => cmd_blueprint_list(sim),
317-
Commands::BlueprintFromInventory(args) => {
318-
cmd_blueprint_from_inventory(sim, args)
319-
}
320317
Commands::BlueprintEdit(args) => cmd_blueprint_edit(sim, args),
321318
Commands::BlueprintPlan(args) => cmd_blueprint_plan(sim, args),
322319
Commands::BlueprintShow(args) => cmd_blueprint_show(sim, args),
@@ -374,8 +371,6 @@ enum Commands {
374371

375372
/// list all blueprints
376373
BlueprintList,
377-
/// generate a blueprint that represents the contents of an inventory
378-
BlueprintFromInventory(InventoryArgs),
379374
/// run planner to generate a new blueprint
380375
BlueprintPlan(BlueprintPlanArgs),
381376
/// edit contents of a blueprint directly
@@ -718,38 +713,6 @@ fn cmd_blueprint_list(
718713
Ok(Some(table))
719714
}
720715

721-
fn cmd_blueprint_from_inventory(
722-
sim: &mut ReconfiguratorSim,
723-
args: InventoryArgs,
724-
) -> anyhow::Result<Option<String>> {
725-
let collection_id = args.collection_id;
726-
let collection = sim
727-
.collections
728-
.get(&collection_id)
729-
.ok_or_else(|| anyhow!("no such collection: {}", collection_id))?;
730-
let dns_version = Generation::new();
731-
let planning_input = sim
732-
.system
733-
.to_planning_input_builder()
734-
.context("generating planning_input builder")?
735-
.build();
736-
let creator = "reconfigurator-sim";
737-
let blueprint = BlueprintBuilder::build_initial_from_collection(
738-
collection,
739-
dns_version,
740-
dns_version,
741-
planning_input.all_sled_ids(SledFilter::All),
742-
creator,
743-
)
744-
.context("building collection")?;
745-
let rv = format!(
746-
"generated blueprint {} from inventory collection {}",
747-
blueprint.id, collection_id
748-
);
749-
sim.blueprint_insert_new(blueprint);
750-
Ok(Some(rv))
751-
}
752-
753716
fn cmd_blueprint_plan(
754717
sim: &mut ReconfiguratorSim,
755718
args: BlueprintPlanArgs,

nexus/db-queries/src/db/datastore/deployment.rs

Lines changed: 50 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,12 +1263,12 @@ mod tests {
12631263
use nexus_inventory::now_db_precision;
12641264
use nexus_reconfigurator_planning::blueprint_builder::BlueprintBuilder;
12651265
use nexus_reconfigurator_planning::blueprint_builder::Ensure;
1266+
use nexus_reconfigurator_planning::example::example;
12661267
use nexus_test_utils::db::test_setup_database;
12671268
use nexus_types::deployment::BlueprintZoneDisposition;
12681269
use nexus_types::deployment::BlueprintZoneFilter;
12691270
use nexus_types::deployment::PlanningInput;
12701271
use nexus_types::deployment::PlanningInputBuilder;
1271-
use nexus_types::deployment::Policy;
12721272
use nexus_types::deployment::SledDetails;
12731273
use nexus_types::deployment::SledDisk;
12741274
use nexus_types::deployment::SledFilter;
@@ -1279,7 +1279,6 @@ mod tests {
12791279
use nexus_types::external_api::views::SledState;
12801280
use nexus_types::inventory::Collection;
12811281
use omicron_common::address::Ipv6Subnet;
1282-
use omicron_common::api::external::Generation;
12831282
use omicron_common::disk::DiskIdentity;
12841283
use omicron_test_utils::dev;
12851284
use omicron_uuid_kinds::PhysicalDiskUuid;
@@ -1288,6 +1287,7 @@ mod tests {
12881287
use pretty_assertions::assert_eq;
12891288
use rand::thread_rng;
12901289
use rand::Rng;
1290+
use slog::Logger;
12911291
use std::mem;
12921292
use std::net::Ipv6Addr;
12931293

@@ -1359,65 +1359,32 @@ mod tests {
13591359
}
13601360
}
13611361

1362-
// Create a `Policy` that contains all the sleds found in `collection`
1363-
fn policy_from_collection(collection: &Collection) -> Policy {
1364-
Policy {
1365-
service_ip_pool_ranges: Vec::new(),
1366-
target_nexus_zone_count: collection
1367-
.all_omicron_zones()
1368-
.filter(|z| z.zone_type.is_nexus())
1369-
.count(),
1370-
}
1371-
}
1362+
fn representative(
1363+
log: &Logger,
1364+
test_name: &str,
1365+
) -> (Collection, PlanningInput, Blueprint) {
1366+
// We'll start with an example system.
1367+
let (mut base_collection, planning_input, mut blueprint) =
1368+
example(log, test_name, 3);
13721369

1373-
fn representative() -> (Collection, PlanningInput, Blueprint) {
1374-
// We'll start with a representative collection...
1370+
// Take a more thorough collection representative (includes SPs,
1371+
// etc.)...
13751372
let mut collection =
13761373
nexus_inventory::examples::representative().builder.build();
13771374

1378-
// ...and then mutate it such that the omicron zones it reports match
1379-
// the sled agent IDs it reports. Steal the sled agent info and drop the
1380-
// fake sled-agent IDs:
1381-
let mut empty_map = BTreeMap::new();
1382-
mem::swap(&mut empty_map, &mut collection.sled_agents);
1383-
let mut sled_agents = empty_map.into_values().collect::<Vec<_>>();
1384-
1385-
// Now reinsert them with IDs pulled from the omicron zones. This
1386-
// assumes we have more fake sled agents than omicron zones, which is
1387-
// currently true for the representative collection.
1388-
for &sled_id in collection.omicron_zones.keys() {
1389-
let some_sled_agent = sled_agents.pop().expect(
1390-
"fewer representative sled agents than \
1391-
representative omicron zones sleds",
1392-
);
1393-
collection.sled_agents.insert(sled_id, some_sled_agent);
1394-
}
1375+
// ... and replace its sled agent and Omicron zones with those from our
1376+
// example system.
1377+
mem::swap(
1378+
&mut collection.sled_agents,
1379+
&mut base_collection.sled_agents,
1380+
);
1381+
mem::swap(
1382+
&mut collection.omicron_zones,
1383+
&mut base_collection.omicron_zones,
1384+
);
13951385

1396-
let policy = policy_from_collection(&collection);
1397-
let planning_input = {
1398-
let mut builder = PlanningInputBuilder::new(
1399-
policy,
1400-
Generation::new(),
1401-
Generation::new(),
1402-
);
1403-
for (sled_id, agent) in &collection.sled_agents {
1404-
builder
1405-
.add_sled(
1406-
*sled_id,
1407-
fake_sled_details(Some(*agent.sled_agent_address.ip())),
1408-
)
1409-
.expect("failed to add sled to representative");
1410-
}
1411-
builder.build()
1412-
};
1413-
let blueprint = BlueprintBuilder::build_initial_from_collection(
1414-
&collection,
1415-
Generation::new(),
1416-
Generation::new(),
1417-
planning_input.all_sled_ids(SledFilter::All),
1418-
"test",
1419-
)
1420-
.unwrap();
1386+
// Treat this blueprint as the initial blueprint for the system.
1387+
blueprint.parent_blueprint_id = None;
14211388

14221389
(collection, planning_input, blueprint)
14231390
}
@@ -1442,17 +1409,11 @@ mod tests {
14421409
let mut db = test_setup_database(&logctx.log).await;
14431410
let (opctx, datastore) = datastore_test(&logctx, &db).await;
14441411

1445-
// Create an empty collection and a blueprint from it
1446-
let collection =
1447-
nexus_inventory::CollectionBuilder::new("test").build();
1448-
let blueprint1 = BlueprintBuilder::build_initial_from_collection(
1449-
&collection,
1450-
Generation::new(),
1451-
Generation::new(),
1412+
// Create an empty blueprint from it
1413+
let blueprint1 = BlueprintBuilder::build_empty_with_sleds(
14521414
std::iter::empty(),
14531415
"test",
1454-
)
1455-
.unwrap();
1416+
);
14561417
let authz_blueprint = authz_blueprint_from_id(blueprint1.id);
14571418

14581419
// Trying to read it from the database should fail with the relevant
@@ -1471,7 +1432,7 @@ mod tests {
14711432
let blueprint_read = datastore
14721433
.blueprint_read(&opctx, &authz_blueprint)
14731434
.await
1474-
.expect("failed to read collection back");
1435+
.expect("failed to read blueprint back");
14751436
assert_eq!(blueprint1, blueprint_read);
14761437
assert_eq!(
14771438
blueprint_list_all_ids(&opctx, &datastore).await,
@@ -1501,13 +1462,15 @@ mod tests {
15011462

15021463
#[tokio::test]
15031464
async fn test_representative_blueprint() {
1465+
const TEST_NAME: &str = "test_representative_blueprint";
15041466
// Setup
1505-
let logctx = dev::test_setup_log("test_representative_blueprint");
1467+
let logctx = dev::test_setup_log(TEST_NAME);
15061468
let mut db = test_setup_database(&logctx.log).await;
15071469
let (opctx, datastore) = datastore_test(&logctx, &db).await;
15081470

15091471
// Create a cohesive representative collection/policy/blueprint
1510-
let (collection, planning_input, blueprint1) = representative();
1472+
let (collection, planning_input, blueprint1) =
1473+
representative(&logctx.log, TEST_NAME);
15111474
let authz_blueprint1 = authz_blueprint_from_id(blueprint1.id);
15121475

15131476
// Write it to the database and read it back.
@@ -1632,10 +1595,23 @@ mod tests {
16321595
let blueprint2 = builder.build();
16331596
let authz_blueprint2 = authz_blueprint_from_id(blueprint2.id);
16341597

1598+
let diff = blueprint2.diff_since_blueprint(&blueprint1).unwrap();
1599+
println!("b1 -> b2: {}", diff.display());
1600+
println!("b1 disks: {:?}", blueprint1.blueprint_disks);
1601+
println!("b2 disks: {:?}", blueprint2.blueprint_disks);
16351602
// Check that we added the new sled, as well as its disks and zones.
16361603
assert_eq!(
1637-
blueprint1.blueprint_disks.len() + new_sled_zpools.len(),
1638-
blueprint2.blueprint_disks.len(),
1604+
blueprint1
1605+
.blueprint_disks
1606+
.values()
1607+
.map(|c| c.disks.len())
1608+
.sum::<usize>()
1609+
+ new_sled_zpools.len(),
1610+
blueprint2
1611+
.blueprint_disks
1612+
.values()
1613+
.map(|c| c.disks.len())
1614+
.sum::<usize>()
16391615
);
16401616
assert_eq!(
16411617
blueprint1.blueprint_zones.len() + 1,
@@ -1757,16 +1733,10 @@ mod tests {
17571733
// Create three blueprints:
17581734
// * `blueprint1` has no parent
17591735
// * `blueprint2` and `blueprint3` both have `blueprint1` as parent
1760-
let collection =
1761-
nexus_inventory::CollectionBuilder::new("test").build();
1762-
let blueprint1 = BlueprintBuilder::build_initial_from_collection(
1763-
&collection,
1764-
Generation::new(),
1765-
Generation::new(),
1736+
let blueprint1 = BlueprintBuilder::build_empty_with_sleds(
17661737
std::iter::empty(),
17671738
"test1",
1768-
)
1769-
.unwrap();
1739+
);
17701740
let blueprint2 = BlueprintBuilder::new_based_on(
17711741
&logctx.log,
17721742
&blueprint1,
@@ -1911,16 +1881,10 @@ mod tests {
19111881
let (opctx, datastore) = datastore_test(&logctx, &db).await;
19121882

19131883
// Create an initial blueprint and a child.
1914-
let collection =
1915-
nexus_inventory::CollectionBuilder::new("test").build();
1916-
let blueprint1 = BlueprintBuilder::build_initial_from_collection(
1917-
&collection,
1918-
Generation::new(),
1919-
Generation::new(),
1884+
let blueprint1 = BlueprintBuilder::build_empty_with_sleds(
19201885
std::iter::empty(),
19211886
"test1",
1922-
)
1923-
.unwrap();
1887+
);
19241888
let blueprint2 = BlueprintBuilder::new_based_on(
19251889
&logctx.log,
19261890
&blueprint1,

0 commit comments

Comments
 (0)