Skip to content

Commit 8d968c5

Browse files
committed
test_external_dns_external_ips_specified_by_rack_setup()
1 parent ff1b86a commit 8d968c5

File tree

1 file changed

+117
-106
lines changed

1 file changed

+117
-106
lines changed

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

Lines changed: 117 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,11 @@ mod tests {
513513
use nexus_config::NUM_INITIAL_RESERVED_IP_ADDRESSES;
514514
use nexus_db_model::SqlU16;
515515
use nexus_reconfigurator_planning::blueprint_builder::BlueprintBuilder;
516+
use nexus_reconfigurator_planning::blueprint_editor::ExternalNetworkingAllocator;
517+
use nexus_reconfigurator_planning::example::ExampleSystemBuilder;
518+
use nexus_reconfigurator_planning::planner::PlannerRng;
516519
use nexus_sled_agent_shared::inventory::OmicronZoneDataset;
520+
use nexus_types::deployment::BlueprintSource;
517521
use nexus_types::deployment::BlueprintTarget;
518522
use nexus_types::deployment::BlueprintZoneConfig;
519523
use nexus_types::deployment::BlueprintZoneImageSource;
@@ -527,6 +531,7 @@ mod tests {
527531
use omicron_common::address::DNS_OPTE_IPV4_SUBNET;
528532
use omicron_common::address::IpRange;
529533
use omicron_common::address::IpRangeIter;
534+
use omicron_common::address::Ipv4Range;
530535
use omicron_common::address::NEXUS_OPTE_IPV4_SUBNET;
531536
use omicron_common::address::NTP_OPTE_IPV4_SUBNET;
532537
use omicron_common::address::NUM_SOURCE_NAT_PORTS;
@@ -535,10 +540,7 @@ mod tests {
535540
use omicron_common::api::external::Vni;
536541
use omicron_common::zpool_name::ZpoolName;
537542
use omicron_test_utils::dev;
538-
use omicron_uuid_kinds::BlueprintUuid;
539543
use omicron_uuid_kinds::ExternalIpUuid;
540-
use omicron_uuid_kinds::ExternalZpoolUuid;
541-
use omicron_uuid_kinds::SledUuid;
542544
use omicron_uuid_kinds::ZpoolUuid;
543545
use oxnet::IpNet;
544546
use std::net::IpAddr;
@@ -1348,149 +1350,158 @@ mod tests {
13481350
const TEST_NAME: &str =
13491351
"test_external_dns_external_ips_specified_by_rack_setup";
13501352

1351-
// Helper closures to reduce boilerplate below.
1353+
// Helper closure to reduce boilerplate below.
13521354
let make_bp_target = |blueprint_id| BlueprintTarget {
13531355
target_id: blueprint_id,
13541356
enabled: false,
13551357
time_made_target: Utc::now(),
13561358
};
1357-
let mut opte_ip_iter = DNS_OPTE_IPV4_SUBNET.addr_iter();
1358-
let mut mac_iter = MacAddr::iter_system();
1359-
let mut make_external_dns_zone = |ip, disposition| {
1360-
let zone_id = OmicronZoneUuid::new_v4();
1361-
let pool = ZpoolName::External(ExternalZpoolUuid::new_v4());
1362-
BlueprintZoneConfig {
1363-
disposition,
1364-
id: zone_id,
1365-
filesystem_pool: pool,
1366-
zone_type: BlueprintZoneType::ExternalDns(
1367-
blueprint_zone_type::ExternalDns {
1368-
dataset: OmicronZoneDataset { pool_name: pool },
1369-
http_address: "[::1]:0".parse().unwrap(),
1370-
dns_address: OmicronZoneExternalFloatingAddr {
1371-
id: ExternalIpUuid::new_v4(),
1372-
addr: SocketAddr::new(ip, 0),
1373-
},
1374-
nic: NetworkInterface {
1375-
id: Uuid::new_v4(),
1376-
kind: NetworkInterfaceKind::Service {
1377-
id: zone_id.into_untyped_uuid(),
1378-
},
1379-
name: "test-external-dns".parse().unwrap(),
1380-
ip: opte_ip_iter.next().unwrap().into(),
1381-
mac: mac_iter.next().unwrap(),
1382-
subnet: IpNet::from(*DNS_OPTE_IPV4_SUBNET),
1383-
vni: Vni::SERVICES_VNI,
1384-
primary: true,
1385-
slot: 0,
1386-
transit_ips: vec![],
1387-
},
1388-
},
1389-
),
1390-
image_source: BlueprintZoneImageSource::InstallDataset,
1391-
}
1392-
};
13931359

13941360
// Set up.
13951361
let logctx = dev::test_setup_log(TEST_NAME);
13961362
let db = TestDatabase::new_with_datastore(&logctx.log).await;
13971363
let (opctx, datastore) = (db.opctx(), db.datastore());
13981364

1399-
// Create a blueprint with one sled and no zones. Insert it and make it
1400-
// the target.
1401-
let sled_id = SledUuid::new_v4();
1402-
let bp0 = BlueprintBuilder::build_empty_with_sleds(
1403-
std::iter::once(sled_id),
1404-
TEST_NAME,
1405-
);
1406-
datastore.blueprint_insert(opctx, &bp0).await.expect("inserted bp0");
1407-
datastore
1408-
.blueprint_target_set_current(opctx, make_bp_target(bp0.id))
1409-
.await
1410-
.expect("made bp0 the target");
1365+
// Create a blueprint with no external DNS zones.
1366+
let (example_system, bp1) =
1367+
ExampleSystemBuilder::new(&opctx.log, TEST_NAME)
1368+
.external_dns_count(0)
1369+
.expect("external DNS count can be 0")
1370+
.build();
1371+
1372+
// Insert the example system's initial empty blueprint and the one we
1373+
// want to test. Advance the target to point to `blueprint`.
1374+
let bp0 = &example_system.initial_blueprint;
1375+
for bp in [bp0, &bp1] {
1376+
datastore.blueprint_insert(opctx, bp).await.expect("inserted bp");
1377+
datastore
1378+
.blueprint_target_set_current(opctx, make_bp_target(bp.id))
1379+
.await
1380+
.expect("made bp the target");
1381+
}
14111382

14121383
// No external DNS zones => no external DNS IPs.
1384+
assert!(
1385+
example_system
1386+
.input
1387+
.external_ip_policy()
1388+
.external_dns_ips()
1389+
.is_empty()
1390+
);
14131391
let external_dns_ips = datastore
14141392
.external_dns_external_ips_specified_by_rack_setup(opctx)
14151393
.await
14161394
.expect("got external DNS IPs");
14171395
assert_eq!(external_dns_ips, BTreeSet::new());
14181396

1419-
// Create a blueprint with three in-service external DNS zones. We
1420-
// should get their IPs back.
1421-
let expected_ips = ["192.168.1.1", "192.168.1.2", "192.168.1.3"]
1422-
.into_iter()
1423-
.map(|ip| ip.parse::<IpAddr>().unwrap())
1424-
.collect::<BTreeSet<_>>();
1425-
let mut bp1 = bp0.clone();
1426-
bp1.id = BlueprintUuid::new_v4();
1427-
bp1.parent_blueprint_id = Some(bp0.id);
1428-
for &ip in &expected_ips {
1429-
bp1.sleds
1430-
.get_mut(&sled_id)
1431-
.unwrap()
1432-
.zones
1433-
.insert_unique(make_external_dns_zone(
1434-
ip,
1435-
BlueprintZoneDisposition::InService,
1436-
))
1437-
.expect("freshly generated zone IDs are unique");
1397+
// Extend the external IP policy to allow for external DNS.
1398+
let all_external_dns_ips = IpRange::V4(Ipv4Range {
1399+
first: "192.168.1.1".parse().unwrap(),
1400+
last: "192.168.1.5".parse().unwrap(),
1401+
});
1402+
let input = {
1403+
let mut policy_builder = example_system
1404+
.input
1405+
.external_ip_policy()
1406+
.clone()
1407+
.into_builder();
1408+
policy_builder
1409+
.push_service_pool_range(all_external_dns_ips)
1410+
.expect("valid range");
1411+
for ip in all_external_dns_ips.iter() {
1412+
policy_builder.add_external_dns_ip(ip).expect("valid IP");
1413+
}
1414+
1415+
let mut input_builder = example_system.input.into_builder();
1416+
input_builder.policy_mut().external_ips = policy_builder.build();
1417+
input_builder.build()
1418+
};
1419+
1420+
// Add an in-service external DNS zone for each IP.
1421+
let mut builder = BlueprintBuilder::new_based_on(
1422+
&opctx.log,
1423+
&bp1,
1424+
&input,
1425+
TEST_NAME,
1426+
PlannerRng::from_entropy(),
1427+
)
1428+
.expect("created builder");
1429+
1430+
let mut external_networking_alloc =
1431+
ExternalNetworkingAllocator::from_current_zones(
1432+
&builder,
1433+
input.external_ip_policy(),
1434+
)
1435+
.expect("created allocator");
1436+
1437+
let sled_id = bp1.sleds().next().expect("at least 1 sled exists");
1438+
for _ in all_external_dns_ips.iter() {
1439+
builder
1440+
.sled_add_zone_external_dns(
1441+
sled_id,
1442+
BlueprintZoneImageSource::InstallDataset,
1443+
external_networking_alloc
1444+
.for_new_external_dns()
1445+
.expect("got IP for external DNS"),
1446+
)
1447+
.expect("added external DNS");
14381448
}
14391449

1440-
// Insert bp1 and make it the target. Confirm we get back the expected
1450+
// Insert bp2 and make it the target. Confirm we get back the expected
14411451
// external DNS IPs.
1442-
datastore.blueprint_insert(opctx, &bp1).await.expect("inserted bp1");
1452+
let bp2 = builder.build(BlueprintSource::Test);
1453+
let expected_ips = all_external_dns_ips.iter().collect::<BTreeSet<_>>();
1454+
datastore.blueprint_insert(opctx, &bp2).await.expect("inserted bp2");
14431455
datastore
1444-
.blueprint_target_set_current(opctx, make_bp_target(bp1.id))
1456+
.blueprint_target_set_current(opctx, make_bp_target(bp2.id))
14451457
.await
1446-
.expect("made bp1 the target");
1458+
.expect("made bp2 the target");
14471459
let external_dns_ips = datastore
14481460
.external_dns_external_ips_specified_by_rack_setup(opctx)
14491461
.await
14501462
.expect("got external DNS IPs");
14511463
assert_eq!(external_dns_ips, expected_ips);
14521464

1453-
// Create a third blueprint with multiple expunged external DNS zones
1454-
// covering a couple additional IPs. Those should also be returned.
1455-
let extra_ips = ["192.168.1.4", "192.168.1.5"]
1456-
.into_iter()
1457-
.map(|ip| ip.parse::<IpAddr>().unwrap())
1465+
// Create a new blueprint that expunges two of those zones.
1466+
let mut builder = BlueprintBuilder::new_based_on(
1467+
&opctx.log,
1468+
&bp2,
1469+
&input,
1470+
TEST_NAME,
1471+
PlannerRng::from_entropy(),
1472+
)
1473+
.expect("created builder");
1474+
1475+
let to_expunge = builder
1476+
.current_zones(BlueprintZoneDisposition::is_in_service)
1477+
.filter_map(|(sled_id, zone)| {
1478+
if zone.zone_type.is_external_dns() {
1479+
Some((sled_id, zone.id))
1480+
} else {
1481+
None
1482+
}
1483+
})
1484+
.take(2)
14581485
.collect::<BTreeSet<_>>();
1459-
assert_eq!(expected_ips.intersection(&extra_ips).count(), 0);
1460-
1461-
let mut bp2 = bp1.clone();
1462-
bp2.id = BlueprintUuid::new_v4();
1463-
bp2.parent_blueprint_id = Some(bp1.id);
1464-
for &ip in &extra_ips {
1465-
for i in 0..4 {
1466-
bp2.sleds
1467-
.get_mut(&sled_id)
1468-
.unwrap()
1469-
.zones
1470-
.insert_unique(make_external_dns_zone(
1471-
ip,
1472-
BlueprintZoneDisposition::Expunged {
1473-
as_of_generation: Generation::new(),
1474-
ready_for_cleanup: i % 2 == 0,
1475-
},
1476-
))
1477-
.expect("freshly generated zone IDs are unique");
1478-
}
1486+
assert_eq!(to_expunge.len(), 2);
1487+
1488+
for (sled_id, zone_id) in to_expunge {
1489+
builder.sled_expunge_zone(sled_id, zone_id).expect("expunged zone");
14791490
}
14801491

1481-
// Insert bp1 and make it the target. Confirm we get back the expected
1492+
// Insert bp3 and make it the target. Confirm we still get back all five
14821493
// external DNS IPs.
1483-
datastore.blueprint_insert(opctx, &bp2).await.expect("inserted bp2");
1494+
let bp3 = builder.build(BlueprintSource::Test);
1495+
let expected_ips = all_external_dns_ips.iter().collect::<BTreeSet<_>>();
1496+
datastore.blueprint_insert(opctx, &bp3).await.expect("inserted bp3");
14841497
datastore
1485-
.blueprint_target_set_current(opctx, make_bp_target(bp2.id))
1498+
.blueprint_target_set_current(opctx, make_bp_target(bp3.id))
14861499
.await
1487-
.expect("made bp2 the target");
1500+
.expect("made bp3 the target");
14881501
let external_dns_ips = datastore
14891502
.external_dns_external_ips_specified_by_rack_setup(opctx)
14901503
.await
14911504
.expect("got external DNS IPs");
1492-
let expected_ips =
1493-
expected_ips.union(&extra_ips).copied().collect::<BTreeSet<_>>();
14941505
assert_eq!(external_dns_ips, expected_ips);
14951506

14961507
// Clean up.

0 commit comments

Comments
 (0)