Skip to content

Commit

Permalink
share query to fetch pools for silo
Browse files Browse the repository at this point in the history
  • Loading branch information
david-crespo committed Jan 19, 2024
1 parent 7685d47 commit 9e8500d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 46 deletions.
53 changes: 8 additions & 45 deletions nexus/db-queries/src/db/datastore/ip_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,44 +79,6 @@ impl DataStore {
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
}

/// List IP pools linked to the current silo
pub async fn current_silo_ip_pool_list(
&self,
opctx: &OpContext,
pagparams: &PaginatedBy<'_>,
) -> ListResultVec<(IpPool, IpPoolResource)> {
use db::schema::ip_pool;
use db::schema::ip_pool_resource;

// From the developer user's point of view, we treat IP pools linked to
// their silo as silo resources, so they can list them if they can list
// silo children
let authz_silo =
opctx.authn.silo_required().internal_context("listing IP pools")?;
opctx.authorize(authz::Action::ListChildren, &authz_silo).await?;

let silo_id = authz_silo.id();

match pagparams {
PaginatedBy::Id(pagparams) => {
paginated(ip_pool::table, ip_pool::id, pagparams)
}
PaginatedBy::Name(pagparams) => paginated(
ip_pool::table,
ip_pool::name,
&pagparams.map_name(|n| Name::ref_cast(n)),
),
}
.inner_join(ip_pool_resource::table)
.filter(ip_pool_resource::resource_type.eq(IpPoolResourceType::Silo))
.filter(ip_pool_resource::resource_id.eq(silo_id))
.filter(ip_pool::time_deleted.is_null())
.select(<(IpPool, IpPoolResource)>::as_select())
.get_results_async(&*self.pool_connection_authorized(opctx).await?)
.await
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
}

/// Look up whether the given pool is available to users in the current
/// silo, i.e., whether there is an entry in the association table linking
/// the pool with that silo
Expand Down Expand Up @@ -423,9 +385,7 @@ impl DataStore {
.filter(ip_pool_resource::resource_type.eq(IpPoolResourceType::Silo))
.filter(ip_pool::time_deleted.is_null())
.select(<(IpPool, IpPoolResource)>::as_select())
.load_async::<(IpPool, IpPoolResource)>(
&*self.pool_connection_authorized(opctx).await?,
)
.load_async(&*self.pool_connection_authorized(opctx).await?)
.await
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
}
Expand Down Expand Up @@ -897,8 +857,11 @@ mod test {
.await
.expect("Should list IP pools");
assert_eq!(all_pools.len(), 0);

let authz_silo = opctx.authn.silo_required().unwrap();

let silo_pools = datastore
.current_silo_ip_pool_list(&opctx, &pagbyid)
.silo_ip_pool_list(&opctx, &authz_silo, &pagbyid)
.await
.expect("Should list silo IP pools");
assert_eq!(silo_pools.len(), 0);
Expand All @@ -923,7 +886,7 @@ mod test {
.expect("Should list IP pools");
assert_eq!(all_pools.len(), 1);
let silo_pools = datastore
.current_silo_ip_pool_list(&opctx, &pagbyid)
.silo_ip_pool_list(&opctx, &authz_silo, &pagbyid)
.await
.expect("Should list silo IP pools");
assert_eq!(silo_pools.len(), 0);
Expand Down Expand Up @@ -959,7 +922,7 @@ mod test {

// now it shows up in the silo list
let silo_pools = datastore
.current_silo_ip_pool_list(&opctx, &pagbyid)
.silo_ip_pool_list(&opctx, &authz_silo, &pagbyid)
.await
.expect("Should list silo IP pools");
assert_eq!(silo_pools.len(), 1);
Expand Down Expand Up @@ -1029,7 +992,7 @@ mod test {

// and silo pools list is empty again
let silo_pools = datastore
.current_silo_ip_pool_list(&opctx, &pagbyid)
.silo_ip_pool_list(&opctx, &authz_silo, &pagbyid)
.await
.expect("Should list silo IP pools");
assert_eq!(silo_pools.len(), 0);
Expand Down
19 changes: 18 additions & 1 deletion nexus/src/app/ip_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use omicron_common::api::external::CreateResult;
use omicron_common::api::external::DataPageParams;
use omicron_common::api::external::DeleteResult;
use omicron_common::api::external::Error;
use omicron_common::api::external::InternalContext;
use omicron_common::api::external::ListResultVec;
use omicron_common::api::external::LookupResult;
use omicron_common::api::external::NameOrId;
Expand Down Expand Up @@ -79,7 +80,15 @@ impl super::Nexus {
opctx: &OpContext,
pagparams: &PaginatedBy<'_>,
) -> ListResultVec<(db::model::IpPool, db::model::IpPoolResource)> {
self.db_datastore.current_silo_ip_pool_list(opctx, pagparams).await
let authz_silo =
opctx.authn.silo_required().internal_context("listing IP pools")?;

// From the developer user's point of view, we treat IP pools linked to
// their silo as silo resources, so they can list them if they can list
// silo children
opctx.authorize(authz::Action::ListChildren, &authz_silo).await?;

self.db_datastore.silo_ip_pool_list(opctx, &authz_silo, pagparams).await
}

// Look up pool by name or ID, but only return it if it's linked to the
Expand Down Expand Up @@ -109,6 +118,10 @@ impl super::Nexus {
) -> ListResultVec<db::model::IpPoolResource> {
let (.., authz_pool) =
pool_lookup.lookup_for(authz::Action::ListChildren).await?;

// check ability to list silos in general
opctx.authorize(authz::Action::ListChildren, &authz::FLEET).await?;

self.db_datastore.ip_pool_silo_list(opctx, &authz_pool, pagparams).await
}

Expand All @@ -121,6 +134,10 @@ impl super::Nexus {
) -> ListResultVec<(db::model::IpPool, db::model::IpPoolResource)> {
let (.., authz_silo) =
silo_lookup.lookup_for(authz::Action::Read).await?;
// check ability to list pools in general
opctx
.authorize(authz::Action::ListChildren, &authz::IP_POOL_LIST)
.await?;
self.db_datastore.silo_ip_pool_list(opctx, &authz_silo, pagparams).await
}

Expand Down

0 comments on commit 9e8500d

Please sign in to comment.