Skip to content

Commit 8df03b3

Browse files
authored
Fix IP pool silos pagination bug (#5847)
Closes #5837 - [x] Write test reproducing the bug - [x] Fix the bug
1 parent 152f61c commit 8df03b3

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ impl DataStore {
426426

427427
paginated(
428428
ip_pool_resource::table,
429-
ip_pool_resource::ip_pool_id,
429+
ip_pool_resource::resource_id,
430430
pagparams,
431431
)
432432
.inner_join(ip_pool::table)

nexus/tests/integration_tests/ip_pools.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,54 @@ async fn test_ip_pool_pagination(cptestctx: &ControlPlaneTestContext) {
724724
assert_eq!(get_names(next_page.items), &pool_names[5..8]);
725725
}
726726

727+
#[nexus_test]
728+
async fn test_ip_pool_silos_pagination(cptestctx: &ControlPlaneTestContext) {
729+
let client = &cptestctx.external_client;
730+
731+
// one pool, and there should be no linked silos
732+
create_pool(client, "p0").await;
733+
let silos_p0 = silos_for_pool(client, "p0").await;
734+
assert_eq!(silos_p0.items.len(), 0);
735+
736+
// create and link some silos. we need to use discoverable silos because
737+
// non-discoverable silos, while linkable, are filtered out of the list of
738+
// linked silos for a pool
739+
let mut silo_ids = vec![];
740+
for i in 1..=8 {
741+
let name = format!("silo-{}", i);
742+
let silo =
743+
create_silo(&client, &name, true, SiloIdentityMode::SamlJit).await;
744+
silo_ids.push(silo.id());
745+
link_ip_pool(client, "p0", &silo.id(), false).await;
746+
}
747+
748+
// we paginate by ID, so these should be in order to match
749+
silo_ids.sort();
750+
751+
let base_url = "/v1/system/ip-pools/p0/silos";
752+
let first_five_url = format!("{}?limit=5", base_url);
753+
let first_five =
754+
objects_list_page_authz::<IpPoolSiloLink>(client, &first_five_url)
755+
.await;
756+
assert!(first_five.next_page.is_some());
757+
assert_eq!(
758+
first_five.items.iter().map(|s| s.silo_id).collect::<Vec<_>>(),
759+
&silo_ids[0..5]
760+
);
761+
762+
let next_page_url = format!(
763+
"{}?limit=5&page_token={}",
764+
base_url,
765+
first_five.next_page.unwrap()
766+
);
767+
let next_page =
768+
objects_list_page_authz::<IpPoolSiloLink>(client, &next_page_url).await;
769+
assert_eq!(
770+
next_page.items.iter().map(|s| s.silo_id).collect::<Vec<_>>(),
771+
&silo_ids[5..8]
772+
);
773+
}
774+
727775
/// helper to make tests less ugly
728776
fn get_names(pools: Vec<IpPool>) -> Vec<String> {
729777
pools.iter().map(|p| p.identity.name.to_string()).collect()

0 commit comments

Comments
 (0)