Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions nexus/db-model/src/external_subnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ use nexus_db_schema::schema::subnet_pool;
use nexus_db_schema::schema::subnet_pool_member;
use nexus_db_schema::schema::subnet_pool_silo_link;
use nexus_types::external_api::params;
use nexus_types::external_api::views;
use nexus_types::identity::Resource;
use omicron_common::api::external;
use omicron_common::api::external::Error;
use omicron_uuid_kinds::GenericUuid;
use omicron_uuid_kinds::InstanceKind;
use omicron_uuid_kinds::SubnetPoolKind;
use omicron_uuid_kinds::SubnetPoolMemberKind;
Expand Down Expand Up @@ -72,6 +75,12 @@ impl SubnetPool {
}
}

impl From<SubnetPool> for views::SubnetPool {
fn from(value: SubnetPool) -> Self {
Self { identity: value.identity(), ip_version: value.ip_version.into() }
}
}

#[derive(AsChangeset, Clone, Debug)]
#[diesel(table_name = subnet_pool)]
pub struct SubnetPoolUpdate {
Expand All @@ -80,6 +89,16 @@ pub struct SubnetPoolUpdate {
pub time_modified: DateTime<Utc>,
}

impl From<params::SubnetPoolUpdate> for SubnetPoolUpdate {
fn from(value: params::SubnetPoolUpdate) -> Self {
Self {
name: value.identity.name.map(Into::into),
description: value.identity.description,
time_modified: Utc::now(),
}
}
}

/// A member of a Subnet Pool.
#[derive(
Clone, Debug, Deserialize, PartialEq, Selectable, Serialize, Queryable,
Expand All @@ -97,6 +116,19 @@ pub struct SubnetPoolMember {
rcgen: Generation,
}

impl From<SubnetPoolMember> for views::SubnetPoolMember {
fn from(value: SubnetPoolMember) -> Self {
Self {
id: value.id.into_untyped_uuid(),
time_created: value.time_created,
subnet_pool_id: value.subnet_pool_id.into_untyped_uuid(),
subnet: value.subnet.into(),
min_prefix_length: value.min_prefix_length.into(),
max_prefix_length: value.max_prefix_length.into(),
}
}
}

impl SubnetPoolMember {
pub fn new(
params: &params::SubnetPoolMemberAdd,
Expand Down Expand Up @@ -204,6 +236,21 @@ pub struct ExternalSubnet {
pub instance_id: Option<DbTypedUuid<InstanceKind>>,
}

impl From<ExternalSubnet> for views::ExternalSubnet {
fn from(value: ExternalSubnet) -> Self {
Self {
identity: value.identity(),
subnet: value.subnet.into(),
project_id: value.project_id,
subnet_pool_id: value.subnet_pool_id.into_untyped_uuid(),
subnet_pool_member_id: value
.subnet_pool_member_id
.into_untyped_uuid(),
instance_id: value.instance_id.map(|id| id.into_untyped_uuid()),
}
}
}

#[derive(AsChangeset, Clone, Debug)]
#[diesel(table_name = external_subnet)]
pub struct ExternalSubnetUpdate {
Expand Down
38 changes: 30 additions & 8 deletions nexus/db-queries/src/db/datastore/external_subnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use nexus_db_model::ExternalSubnet;
use nexus_db_model::ExternalSubnetIdentity;
use nexus_db_model::ExternalSubnetUpdate;
use nexus_db_model::IpNet;
use nexus_db_model::IpVersion;
use nexus_db_model::Name;
use nexus_db_model::SubnetPool;
use nexus_db_model::SubnetPoolMember;
Expand Down Expand Up @@ -103,7 +104,9 @@ impl DataStore {
opctx: &OpContext,
params: params::SubnetPoolCreate,
) -> CreateResult<SubnetPool> {
opctx.authorize(authz::Action::CreateChild, &authz::FLEET).await?;
opctx
.authorize(authz::Action::CreateChild, &authz::SUBNET_POOL_LIST)
.await?;
use nexus_db_schema::schema::subnet_pool::dsl;
let pool = SubnetPool::new(params.identity, params.ip_version.into());
diesel::insert_into(dsl::subnet_pool)
Expand Down Expand Up @@ -174,7 +177,7 @@ impl DataStore {
opctx: &OpContext,
authz_pool: &authz::SubnetPool,
updates: SubnetPoolUpdate,
) -> UpdateResult<()> {
) -> UpdateResult<SubnetPool> {
use nexus_db_schema::schema::subnet_pool::dsl;
opctx.authorize(authz::Action::Modify, authz_pool).await?;
let conn = self.pool_connection_authorized(opctx).await?;
Expand All @@ -184,10 +187,10 @@ impl DataStore {
.filter(dsl::time_deleted.is_null()),
)
.set(updates)
.execute_async(&*conn)
.returning(SubnetPool::as_returning())
.get_result_async(&*conn)
.await
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
.map(|_| ())
}

/// Link a Subnet Pool to a Silo.
Expand Down Expand Up @@ -310,9 +313,24 @@ impl DataStore {
&self,
opctx: &OpContext,
authz_pool: &authz::SubnetPool,
db_pool: &SubnetPool,
params: &params::SubnetPoolMemberAdd,
) -> CreateResult<SubnetPoolMember> {
opctx.authorize(authz::Action::CreateChild, authz_pool).await?;

// First check we're adding members of the same IP version.
let pool_version = db_pool.ip_version;
let member_version = match params.subnet {
oxnet::IpNet::V4(_) => IpVersion::V4,
oxnet::IpNet::V6(_) => IpVersion::V6,
};
if pool_version != member_version {
return Err(Error::invalid_request(&format!(
"Cannot add IP{} members to IP{} Subnet Pool",
member_version, pool_version,
)));
}

let member = SubnetPoolMember::new(params, authz_pool.id())?;
insert_subnet_pool_member_query(&member)
.get_result_async(&*self.pool_connection_authorized(opctx).await?)
Expand All @@ -338,6 +356,7 @@ impl DataStore {
opctx.authorize(authz::Action::ListChildren, pool).await?;
paginated(dsl::subnet_pool_member, dsl::subnet, pagparams)
.filter(dsl::subnet_pool_id.eq(to_db_typed_uuid(pool.id())))
.filter(dsl::time_deleted.is_null())
.select(SubnetPoolMember::as_select())
.get_results_async(&*self.pool_connection_authorized(opctx).await?)
.await
Expand Down Expand Up @@ -680,7 +699,7 @@ mod tests {
max_prefix_length: Some(24),
};
let member = datastore
.add_subnet_pool_member(opctx, &authz_pool, &params)
.add_subnet_pool_member(opctx, &authz_pool, &db_pool, &params)
.await
.expect("able to create subnet pool member");

Expand Down Expand Up @@ -742,7 +761,7 @@ mod tests {
let pool_id = NameOrId::Id(pool.identity.id.into_untyped_uuid());

// Re-fetch to get the authz object
let (authz_pool, _db_pool) = datastore
let (authz_pool, db_pool) = datastore
.lookup_subnet_pool(opctx, &pool_id)
.fetch()
.await
Expand All @@ -755,7 +774,7 @@ mod tests {
max_prefix_length: Some(24),
};
let _member = datastore
.add_subnet_pool_member(opctx, &authz_pool, &params)
.add_subnet_pool_member(opctx, &authz_pool, &db_pool, &params)
.await
.expect("able to create subnet pool member");

Expand All @@ -767,7 +786,7 @@ mod tests {
max_prefix_length: Some(26),
};
let err = datastore
.add_subnet_pool_member(opctx, &authz_pool, &params)
.add_subnet_pool_member(opctx, &authz_pool, &db_pool, &params)
.await
.expect_err("failure to create overlapping subnet member");
let Error::InvalidRequest { message } = &err else {
Expand Down Expand Up @@ -1071,6 +1090,7 @@ mod tests {
.add_subnet_pool_member(
opctx,
&authz_pool,
&db_pool,
&SubnetPoolMemberAdd {
subnet,
min_prefix_length: Some(48),
Expand Down Expand Up @@ -2698,6 +2718,7 @@ mod tests {
.add_subnet_pool_member(
opctx,
&authz_pool,
&db_pool,
&SubnetPoolMemberAdd {
subnet: "255.255.255.0/24".parse().unwrap(),
min_prefix_length: Some(24),
Expand Down Expand Up @@ -2841,6 +2862,7 @@ mod tests {
.add_subnet_pool_member(
opctx,
&authz_pool,
&db_pool,
&SubnetPoolMemberAdd {
subnet: "fd00::/48".parse().unwrap(),
min_prefix_length: None,
Expand Down
1 change: 1 addition & 0 deletions nexus/db-queries/src/db/datastore/ip_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5974,6 +5974,7 @@ mod test {
.add_subnet_pool_member(
opctx,
&authz_pool,
&db_pool,
&SubnetPoolMemberAdd {
subnet: "fd00::/48".parse().unwrap(),
min_prefix_length: None,
Expand Down
Loading
Loading