Skip to content

Commit

Permalink
WIP: refactor of operator api networking endpoints
Browse files Browse the repository at this point in the history
WIP: refactor address lot apis
  • Loading branch information
Levon Tarver committed Jul 4, 2024
1 parent a8b3ce2 commit cd6c856
Show file tree
Hide file tree
Showing 14 changed files with 412 additions and 180 deletions.
3 changes: 0 additions & 3 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2034,9 +2034,6 @@ impl std::fmt::Display for Digest {
pub struct AddressLotCreateResponse {
/// The address lot that was created.
pub lot: AddressLot,

/// The address lot blocks that were created.
pub blocks: Vec<AddressLotBlock>,
}

/// Represents an address lot object, containing the id of the lot that can be
Expand Down
133 changes: 67 additions & 66 deletions nexus/db-queries/src/db/datastore/address_lot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use crate::db::pagination::paginated;
use crate::transaction_retry::OptionalError;
use async_bb8_diesel::{AsyncRunQueryDsl, Connection};
use chrono::Utc;
use diesel::pg::sql_types;
use diesel::IntoSql;
use diesel::{ExpressionMethods, QueryDsl, SelectableHelper};
use diesel_dtrace::DTraceConnection;
use ipnetwork::IpNetwork;
Expand All @@ -27,23 +29,15 @@ use omicron_common::api::external::{
LookupResult, ResourceType,
};
use ref_cast::RefCast;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AddressLotCreateResult {
pub lot: AddressLot,
pub blocks: Vec<AddressLotBlock>,
}

impl DataStore {
pub async fn address_lot_create(
&self,
opctx: &OpContext,
params: &params::AddressLotCreate,
) -> CreateResult<AddressLotCreateResult> {
) -> CreateResult<AddressLot> {
use db::schema::address_lot::dsl as lot_dsl;
use db::schema::address_lot_block::dsl as block_dsl;

let conn = self.pool_connection_authorized(opctx).await?;

Expand Down Expand Up @@ -81,63 +75,7 @@ impl DataStore {
}
};

let desired_blocks: Vec<AddressLotBlock> = params
.blocks
.iter()
.map(|b| {
AddressLotBlock::new(
db_lot.id(),
b.first_address.into(),
b.last_address.into(),
)
})
.collect();

let found_blocks: Vec<AddressLotBlock> =
block_dsl::address_lot_block
.filter(block_dsl::address_lot_id.eq(db_lot.id()))
.filter(
block_dsl::first_address.eq_any(
desired_blocks
.iter()
.map(|b| b.first_address)
.collect::<Vec<_>>(),
),
)
.filter(
block_dsl::last_address.eq_any(
desired_blocks
.iter()
.map(|b| b.last_address)
.collect::<Vec<_>>(),
),
)
.get_results_async(&conn)
.await?;

let mut blocks = vec![];

// If the block is found in the database, use the found block.
// If the block is not found in the database, insert it.
for desired_block in desired_blocks {
let block = match found_blocks.iter().find(|db_b| {
db_b.first_address == desired_block.first_address
&& db_b.last_address == desired_block.last_address
}) {
Some(block) => block.clone(),
None => {
diesel::insert_into(block_dsl::address_lot_block)
.values(desired_block)
.returning(AddressLotBlock::as_returning())
.get_results_async(&conn)
.await?[0]
.clone()
}
};
blocks.push(block);
}

Ok(AddressLotCreateResult { lot: db_lot, blocks })
Ok(db_lot)
})
.await
.map_err(|e| {
Expand Down Expand Up @@ -263,6 +201,69 @@ impl DataStore {
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
}

pub async fn address_lot_block_create(
&self,
opctx: &OpContext,
address_lot_id: Uuid,
params: params::AddressLotBlockCreate,
) -> CreateResult<AddressLotBlock> {
use db::schema::address_lot_block::dsl;

let conn = self.pool_connection_authorized(opctx).await?;

self.transaction_retry_wrapper("address_lot_create")
.transaction(&conn, |conn| async move {
let found_block: Option<AddressLotBlock> =
dsl::address_lot_block
.filter(dsl::address_lot_id.eq(address_lot_id))
.filter(
dsl::first_address
.eq(IpNetwork::from(params.first_address)),
)
.filter(
dsl::last_address
.eq(IpNetwork::from(params.last_address)),
)
.select(AddressLotBlock::as_select())
.limit(1)
.first_async(&conn)
.await
.ok();

let new_block = AddressLotBlock::new(
address_lot_id,
IpNetwork::from(params.first_address),
IpNetwork::from(params.last_address),
);

let db_block = match found_block {
Some(v) => v,
None => {
diesel::insert_into(dsl::address_lot_block)
.values(new_block)
.returning(AddressLotBlock::as_returning())
.get_result_async(&conn)
.await?
}
};

Ok(db_block)
})
.await
.map_err(|e| {
public_error_from_diesel(
e,
ErrorHandler::Conflict(
ResourceType::AddressLotBlock,
&format!(
"block covering range {} - {}",
params.first_address, params.last_address
),
),
)
})
}

pub async fn address_lot_id_for_block_id(
&self,
opctx: &OpContext,
Expand Down
1 change: 0 additions & 1 deletion nexus/db-queries/src/db/datastore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ mod volume;
mod vpc;
mod zpool;

pub use address_lot::AddressLotCreateResult;
pub use dns::DataStoreDnsTest;
pub use dns::DnsVersionUpdateBuilder;
pub use instance::InstanceAndActiveVmm;
Expand Down
53 changes: 36 additions & 17 deletions nexus/src/app/address_lot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use db::model::{AddressLot, AddressLotBlock};
use nexus_db_queries::authz;
use nexus_db_queries::context::OpContext;
use nexus_db_queries::db;
use nexus_db_queries::db::datastore::AddressLotCreateResult;
use nexus_db_queries::db::lookup;
use nexus_db_queries::db::lookup::LookupPath;
use omicron_common::api::external::http_pagination::PaginatedBy;
Expand Down Expand Up @@ -45,9 +44,8 @@ impl super::Nexus {
self: &Arc<Self>,
opctx: &OpContext,
params: params::AddressLotCreate,
) -> CreateResult<AddressLotCreateResult> {
) -> CreateResult<AddressLot> {
opctx.authorize(authz::Action::CreateChild, &authz::FLEET).await?;
validate_blocks(&params)?;
self.db_datastore.address_lot_create(opctx, &params).await
}

Expand All @@ -70,6 +68,29 @@ impl super::Nexus {
self.db_datastore.address_lot_list(opctx, pagparams).await
}

pub(crate) async fn address_lot_block_create(
self: &Arc<Self>,
opctx: &OpContext,
address_lot_id: Uuid,
block: params::AddressLotBlockCreate,
) -> CreateResult<AddressLotBlock> {
opctx.authorize(authz::Action::CreateChild, &authz::FLEET).await?;
validate_block(&block)?;
self.db_datastore
.address_lot_block_create(opctx, address_lot_id, block)
.await
}

pub(crate) async fn address_lot_block_delete(
self: &Arc<Self>,
opctx: &OpContext,
address_lot: &lookup::AddressLot<'_>,
block: params::AddressLotBlockCreate,
) -> DeleteResult {
opctx.authorize(authz::Action::Read, &authz::FLEET).await?;
todo!("delete address lot block")
}

pub(crate) async fn address_lot_block_list(
self: &Arc<Self>,
opctx: &OpContext,
Expand All @@ -84,20 +105,18 @@ impl super::Nexus {
}
}

fn validate_blocks(lot: &params::AddressLotCreate) -> Result<(), Error> {
for b in &lot.blocks {
match (&b.first_address, &b.last_address) {
(IpAddr::V4(first), IpAddr::V4(last)) => {
validate_v4_block(first, last)?
}
(IpAddr::V6(first), IpAddr::V6(last)) => {
validate_v6_block(first, last)?
}
_ => {
return Err(Error::invalid_request(
"Block bounds must be in same address family",
));
}
fn validate_block(block: &params::AddressLotBlockCreate) -> Result<(), Error> {
match (&block.first_address, &block.last_address) {
(IpAddr::V4(first), IpAddr::V4(last)) => {
validate_v4_block(first, last)?
}
(IpAddr::V6(first), IpAddr::V6(last)) => {
validate_v6_block(first, last)?
}
_ => {
return Err(Error::invalid_request(
"Block bounds must be in same address family",
));
}
}
Ok(())
Expand Down
19 changes: 10 additions & 9 deletions nexus/src/app/rack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ impl super::Nexus {

let blocks = vec![ipv4_block];

let address_lot_params = AddressLotCreate { identity, kind, blocks };
let address_lot_params = AddressLotCreate { identity, kind };

match self
.db_datastore
Expand Down Expand Up @@ -425,14 +425,15 @@ impl super::Nexus {
),
},
kind: AddressLotKind::Infra,
blocks: bgp_config
.originate
.iter()
.map(|o| AddressLotBlockCreate {
first_address: o.first_addr().into(),
last_address: o.last_addr().into(),
})
.collect(),
// TODO: Levon - Move to new creation logic
// blocks: bgp_config
// .originate
// .iter()
// .map(|o| AddressLotBlockCreate {
// first_address: o.first_addr().into(),
// last_address: o.last_addr().into(),
// })
// .collect(),
},
)
.await
Expand Down
Loading

0 comments on commit cd6c856

Please sign in to comment.