Skip to content

Commit

Permalink
Working addition/listing of floating IPs, correct DB constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixMcFelix committed Nov 23, 2023
1 parent 4db9048 commit ba0f7a3
Show file tree
Hide file tree
Showing 19 changed files with 298 additions and 79 deletions.
1 change: 1 addition & 0 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,7 @@ pub enum ResourceType {
Zpool,
Vmm,
Ipv4NatEntry,
// ExternalIp,
}

// IDENTITY METADATA
Expand Down
26 changes: 14 additions & 12 deletions nexus/db-model/src/external_ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ pub struct ExternalIp {
pub time_created: DateTime<Utc>,
pub time_modified: DateTime<Utc>,
pub time_deleted: Option<DateTime<Utc>>,
pub ip_pool_id: Option<Uuid>,
pub ip_pool_range_id: Option<Uuid>,
pub ip_pool_id: Uuid,
pub ip_pool_range_id: Uuid,
pub is_service: bool,
// This is Some(_) for:
// - all instance/service SNAT IPs
Expand All @@ -69,6 +69,7 @@ pub struct ExternalIp {
pub ip: IpNetwork,
pub first_port: SqlU16,
pub last_port: SqlU16,
// Only Some(_) for instance Floating IPs
pub project_id: Option<Uuid>,
}

Expand All @@ -93,7 +94,7 @@ pub struct IncompleteExternalIp {
kind: IpKind,
is_service: bool,
parent_id: Option<Uuid>,
pool_id: Option<Uuid>,
pool_id: Uuid,
project_id: Option<Uuid>,
// Optional address requesting that a specific IP address be allocated.
explicit_ip: Option<IpNetwork>,
Expand All @@ -115,7 +116,7 @@ impl IncompleteExternalIp {
kind: IpKind::SNat,
is_service: false,
parent_id: Some(instance_id),
pool_id: Some(pool_id),
pool_id,
project_id: None,
explicit_ip: None,
explicit_port_range: None,
Expand All @@ -131,7 +132,7 @@ impl IncompleteExternalIp {
kind: IpKind::Ephemeral,
is_service: false,
parent_id: Some(instance_id),
pool_id: Some(pool_id),
pool_id,
project_id: None,
explicit_ip: None,
explicit_port_range: None,
Expand All @@ -153,7 +154,7 @@ impl IncompleteExternalIp {
kind: IpKind::Floating,
is_service: false,
parent_id: None,
pool_id: Some(pool_id),
pool_id,
project_id: Some(project_id),
explicit_ip: None,
explicit_port_range: None,
Expand All @@ -166,6 +167,7 @@ impl IncompleteExternalIp {
description: &str,
project_id: Uuid,
explicit_ip: IpAddr,
pool_id: Uuid,
) -> Self {
Self {
id,
Expand All @@ -175,7 +177,7 @@ impl IncompleteExternalIp {
kind: IpKind::Floating,
is_service: false,
parent_id: None,
pool_id: None,
pool_id,
project_id: Some(project_id),
explicit_ip: Some(explicit_ip.into()),
explicit_port_range: None,
Expand All @@ -198,7 +200,7 @@ impl IncompleteExternalIp {
kind: IpKind::Floating,
is_service: true,
parent_id: Some(service_id),
pool_id: Some(pool_id),
pool_id,
project_id: None,
explicit_ip: Some(IpNetwork::from(address)),
explicit_port_range: None,
Expand Down Expand Up @@ -227,7 +229,7 @@ impl IncompleteExternalIp {
kind: IpKind::SNat,
is_service: true,
parent_id: Some(service_id),
pool_id: Some(pool_id),
pool_id,
project_id: None,
explicit_ip: Some(IpNetwork::from(address)),
explicit_port_range,
Expand All @@ -249,7 +251,7 @@ impl IncompleteExternalIp {
kind: IpKind::Floating,
is_service: true,
parent_id: Some(service_id),
pool_id: Some(pool_id),
pool_id,
project_id: None,
explicit_ip: None,
explicit_port_range: None,
Expand All @@ -265,7 +267,7 @@ impl IncompleteExternalIp {
kind: IpKind::SNat,
is_service: true,
parent_id: Some(service_id),
pool_id: Some(pool_id),
pool_id,
project_id: None,
explicit_ip: None,
explicit_port_range: None,
Expand Down Expand Up @@ -300,7 +302,7 @@ impl IncompleteExternalIp {
&self.parent_id
}

pub fn pool_id(&self) -> &Option<Uuid> {
pub fn pool_id(&self) -> &Uuid {
&self.pool_id
}

Expand Down
6 changes: 4 additions & 2 deletions nexus/db-model/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,14 +524,16 @@ table! {
time_created -> Timestamptz,
time_modified -> Timestamptz,
time_deleted -> Nullable<Timestamptz>,
ip_pool_id -> Nullable<Uuid>,
ip_pool_range_id -> Nullable<Uuid>,

ip_pool_id -> Uuid,
ip_pool_range_id -> Uuid,
is_service -> Bool,
parent_id -> Nullable<Uuid>,
kind -> crate::IpKindEnum,
ip -> Inet,
first_port -> Int4,
last_port -> Int4,

project_id -> Nullable<Uuid>,
}
}
Expand Down
48 changes: 40 additions & 8 deletions nexus/db-queries/src/db/datastore/external_ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,20 +132,52 @@ impl DataStore {
pub async fn allocate_floating_ip(
&self,
opctx: &OpContext,
pool_id: Option<Uuid>,
project_id: Uuid,
ip_id: Uuid,
name: &Name,
description: &str,
ip: IpAddr,
ip: Option<IpAddr>,
) -> CreateResult<ExternalIp> {
let data = IncompleteExternalIp::for_floating_explicit(
ip_id,
name,
description,
project_id,
ip,
);
// XXX: mux here to scan *all* project pools in
// current silo for convenience?
let pool_id = if let Some(id) = pool_id {
id
} else {
self.ip_pools_fetch_default(opctx).await?.id()
};

// XXX: Verify that chosen pool comes from my silo.

let data = if let Some(ip) = ip {
IncompleteExternalIp::for_floating_explicit(
ip_id,
name,
description,
project_id,
ip,
pool_id,
)
} else {
IncompleteExternalIp::for_floating(
ip_id,
name,
description,
project_id,
pool_id,
)
};

// TODO: need to disambiguate no IP and/or IP taken
// from resource name collision, and expose those in
// a nice way.
self.allocate_external_ip(opctx, data).await
// .map_err(|e| {
// public_error_from_diesel(
// e,
// ErrorHandler::Conflict(todo!(), name.as_str())
// )
// })
}

/// Allocates a floating IP address for instance usage.
Expand Down
10 changes: 10 additions & 0 deletions nexus/db-queries/src/db/datastore/ip_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ impl DataStore {
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
}

/// Lookup an IP pool within the current silo which contains a target IP
/// address.
pub async fn ip_pools_fetch_for_ip(
&self,
opctx: &OpContext,
ip_addr: std::net::IpAddr,
) -> LookupResult<IpPool> {
todo!()
}

/// Looks up an IP pool intended for internal services.
///
/// This method may require an index by Availability Zone in the future.
Expand Down
12 changes: 6 additions & 6 deletions nexus/db-queries/src/db/datastore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1565,8 +1565,8 @@ mod test {
time_created: now,
time_modified: now,
time_deleted: None,
ip_pool_id: Some(Uuid::new_v4()),
ip_pool_range_id: Some(Uuid::new_v4()),
ip_pool_id: Uuid::new_v4(),
ip_pool_range_id: Uuid::new_v4(),
project_id: None,
is_service: false,
parent_id: Some(instance_id),
Expand Down Expand Up @@ -1626,8 +1626,8 @@ mod test {
time_created: now,
time_modified: now,
time_deleted: None,
ip_pool_id: Some(Uuid::new_v4()),
ip_pool_range_id: Some(Uuid::new_v4()),
ip_pool_id: Uuid::new_v4(),
ip_pool_range_id: Uuid::new_v4(),
project_id: None,
is_service: false,
parent_id: Some(Uuid::new_v4()),
Expand Down Expand Up @@ -1697,8 +1697,8 @@ mod test {
time_created: now,
time_modified: now,
time_deleted: None,
ip_pool_id: Some(Uuid::new_v4()),
ip_pool_range_id: Some(Uuid::new_v4()),
ip_pool_id: Uuid::new_v4(),
ip_pool_range_id: Uuid::new_v4(),
project_id: None,
is_service: false,
parent_id: Some(Uuid::new_v4()),
Expand Down
16 changes: 8 additions & 8 deletions nexus/db-queries/src/db/datastore/rack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1148,31 +1148,31 @@ mod test {
assert_eq!(observed_ip_pool_ranges[0].ip_pool_id, svc_pool.id());

// Verify the allocated external IPs
assert_eq!(dns_external_ip.ip_pool_id, Some(svc_pool.id()));
assert_eq!(dns_external_ip.ip_pool_id, svc_pool.id());
assert_eq!(
dns_external_ip.ip_pool_range_id,
Some(observed_ip_pool_ranges[0].id)
observed_ip_pool_ranges[0].id
);
assert_eq!(dns_external_ip.ip.ip(), external_dns_ip);

assert_eq!(nexus_external_ip.ip_pool_id, Some(svc_pool.id()));
assert_eq!(nexus_external_ip.ip_pool_id, svc_pool.id());
assert_eq!(
nexus_external_ip.ip_pool_range_id,
Some(observed_ip_pool_ranges[0].id)
observed_ip_pool_ranges[0].id
);
assert_eq!(nexus_external_ip.ip.ip(), nexus_ip);

assert_eq!(ntp1_external_ip.ip_pool_id, Some(svc_pool.id()));
assert_eq!(ntp1_external_ip.ip_pool_id, svc_pool.id());
assert_eq!(
ntp1_external_ip.ip_pool_range_id,
Some(observed_ip_pool_ranges[0].id)
observed_ip_pool_ranges[0].id
);
assert_eq!(ntp1_external_ip.ip.ip(), ntp1_ip);

assert_eq!(ntp2_external_ip.ip_pool_id, Some(svc_pool.id()));
assert_eq!(ntp2_external_ip.ip_pool_id, svc_pool.id());
assert_eq!(
ntp2_external_ip.ip_pool_range_id,
Some(observed_ip_pool_ranges[0].id)
observed_ip_pool_ranges[0].id
);
assert_eq!(ntp2_external_ip.ip.ip(), ntp2_ip);

Expand Down
10 changes: 10 additions & 0 deletions nexus/db-queries/src/db/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,7 @@ lookup_resource! {
lookup_resource! {
name = "Project",
ancestors = [ "Silo" ],
// children = [ "Disk", "Instance", "Vpc", "Snapshot", "ProjectImage", "ExternalIp" ],
children = [ "Disk", "Instance", "Vpc", "Snapshot", "ProjectImage" ],
lookup_by_name = true,
soft_deletes = true,
Expand Down Expand Up @@ -728,6 +729,15 @@ lookup_resource! {
primary_key_columns = [ { column_name = "id", rust_type = Uuid } ]
}

// lookup_resource! {
// name = "ExternalIp",
// ancestors = [ "Silo", "Project" ],
// children = [],
// lookup_by_name = true,
// soft_deletes = true,
// primary_key_columns = [ { column_name = "id", rust_type = Uuid } ]
// }

// Miscellaneous resources nested directly below "Fleet"

lookup_resource! {
Expand Down
12 changes: 10 additions & 2 deletions nexus/db-queries/src/db/queries/external_ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ const MAX_PORT: u16 = u16::MAX;
/// <kind> AS kind,
/// candidate_ip AS ip,
/// CAST(candidate_first_port AS INT4) AS first_port,
/// CAST(candidate_last_port AS INT4) AS last_port
/// CAST(candidate_last_port AS INT4) AS last_port,
/// <project_id> AS project_id
/// FROM
/// SELECT * FROM (
/// -- Select all IP addresses by pool and range.
Expand Down Expand Up @@ -371,6 +372,13 @@ impl NextExternalIp {
out.push_identifier(dsl::first_port::NAME)?;
out.push_sql(", CAST(candidate_last_port AS INT4) AS ");
out.push_identifier(dsl::last_port::NAME)?;
out.push_sql(", ");

// Project ID, possibly null
out.push_bind_param::<sql_types::Nullable<sql_types::Uuid>, Option<Uuid>>(self.ip.project_id())?;
out.push_sql(" AS ");
out.push_identifier(dsl::project_id::NAME)?;

out.push_sql(" FROM (");
self.push_address_sequence_subquery(out.reborrow())?;
out.push_sql(") CROSS JOIN (");
Expand Down Expand Up @@ -622,7 +630,7 @@ impl NextExternalIp {
out.push_sql(" WHERE ");
out.push_identifier(dsl::ip_pool_id::NAME)?;
out.push_sql(" = ");
out.push_bind_param::<sql_types::Nullable<sql_types::Uuid>, Option<Uuid>>(self.ip.pool_id())?;
out.push_bind_param::<sql_types::Uuid, Uuid>(self.ip.pool_id())?;
out.push_sql(" AND ");
out.push_identifier(dsl::time_deleted::NAME)?;
out.push_sql(" IS NULL");
Expand Down
Loading

0 comments on commit ba0f7a3

Please sign in to comment.