-
Notifications
You must be signed in to change notification settings - Fork 45
Add IP Pools and contained IP ranges #1253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b2db78f
cc89d65
a20d28f
2f5733d
e9850d7
23c402f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -827,32 +827,6 @@ STORING (vpc_id, subnet_id, is_primary) | |
WHERE | ||
time_deleted IS NULL; | ||
|
||
|
||
CREATE TYPE omicron.public.vpc_router_kind AS ENUM ( | ||
'system', | ||
'custom' | ||
); | ||
|
||
CREATE TABLE omicron.public.vpc_router ( | ||
/* Identity metadata (resource) */ | ||
id UUID PRIMARY KEY, | ||
name STRING(63) NOT NULL, | ||
description STRING(512) NOT NULL, | ||
time_created TIMESTAMPTZ NOT NULL, | ||
time_modified TIMESTAMPTZ NOT NULL, | ||
/* Indicates that the object has been deleted */ | ||
time_deleted TIMESTAMPTZ, | ||
kind omicron.public.vpc_router_kind NOT NULL, | ||
vpc_id UUID NOT NULL, | ||
rcgen INT NOT NULL | ||
); | ||
|
||
CREATE UNIQUE INDEX ON omicron.public.vpc_router ( | ||
vpc_id, | ||
name | ||
) WHERE | ||
time_deleted IS NULL; | ||
|
||
CREATE TYPE omicron.public.vpc_firewall_rule_status AS ENUM ( | ||
'disabled', | ||
'enabled' | ||
|
@@ -904,6 +878,31 @@ CREATE UNIQUE INDEX ON omicron.public.vpc_firewall_rule ( | |
) WHERE | ||
time_deleted IS NULL; | ||
|
||
CREATE TYPE omicron.public.vpc_router_kind AS ENUM ( | ||
'system', | ||
'custom' | ||
); | ||
|
||
CREATE TABLE omicron.public.vpc_router ( | ||
/* Identity metadata (resource) */ | ||
id UUID PRIMARY KEY, | ||
name STRING(63) NOT NULL, | ||
description STRING(512) NOT NULL, | ||
time_created TIMESTAMPTZ NOT NULL, | ||
time_modified TIMESTAMPTZ NOT NULL, | ||
/* Indicates that the object has been deleted */ | ||
time_deleted TIMESTAMPTZ, | ||
kind omicron.public.vpc_router_kind NOT NULL, | ||
vpc_id UUID NOT NULL, | ||
rcgen INT NOT NULL | ||
); | ||
|
||
CREATE UNIQUE INDEX ON omicron.public.vpc_router ( | ||
vpc_id, | ||
name | ||
) WHERE | ||
time_deleted IS NULL; | ||
|
||
CREATE TYPE omicron.public.router_route_kind AS ENUM ( | ||
'default', | ||
'vpc_subnet', | ||
|
@@ -933,6 +932,62 @@ CREATE UNIQUE INDEX ON omicron.public.router_route ( | |
) WHERE | ||
time_deleted IS NULL; | ||
|
||
/* | ||
* An IP Pool, a collection of zero or more IP ranges for external IPs. | ||
*/ | ||
CREATE TABLE omicron.public.ip_pool ( | ||
/* Resource identity metadata */ | ||
id UUID PRIMARY KEY, | ||
name STRING(63) NOT NULL, | ||
description STRING(512) NOT NULL, | ||
time_created TIMESTAMPTZ NOT NULL, | ||
time_modified TIMESTAMPTZ NOT NULL, | ||
time_deleted TIMESTAMPTZ, | ||
|
||
/* The collection's child-resource generation number */ | ||
rcgen INT8 NOT NULL | ||
); | ||
|
||
/* | ||
* Index ensuring uniqueness of IP Pool names, globally. | ||
*/ | ||
CREATE UNIQUE INDEX ON omicron.public.ip_pool ( | ||
name | ||
) WHERE | ||
time_deleted IS NULL; | ||
|
||
/* | ||
* IP Pools are made up of a set of IP ranges, which are start/stop addresses. | ||
* Note that these need not be CIDR blocks or well-behaved subnets with a | ||
* specific netmask. | ||
*/ | ||
CREATE TABLE omicron.public.ip_pool_range ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When it comes time to associate external IPs with instances (or services, like Nexus), do we expect to just use this table as-is, or create a new representation of "assigned" IP addresses? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not entirely sure what that'll look like, but I've had some thoughts. TL;DR: I'm expecting to add the used IPs into things like the So the IP Pools that we've implemented here are a bit of a conflation of two things: IP Pools as defined by RFD 21 and "address sets" defined by RFD 267. The former are addresses used for instance NAT. The latter are more general -- they are a superset of IP Pools, but also used for things like services (e.g, Nexus, DNS) and customer network integration (such as prefixes advertised in some routing protocol like BGP). The work here unfortunately merges these, because we need to get something and it's not entirely clear what's required for address sets yet. That said, I'd expect that the address set table(s) will track what each set is for, and which will direct us to another table, say the |
||
id UUID PRIMARY KEY, | ||
time_created TIMESTAMPTZ NOT NULL, | ||
time_modified TIMESTAMPTZ NOT NULL, | ||
time_deleted TIMESTAMPTZ, | ||
first_address INET NOT NULL, | ||
/* The range is inclusive of the last address. */ | ||
last_address INET NOT NULL, | ||
bnaecker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ip_pool_id UUID NOT NULL | ||
); | ||
|
||
/* | ||
* These help Nexus enforce that the ranges within an IP Pool do not overlap | ||
* with any other ranges. See `nexus/src/db/queries/ip_pool.rs` for the actual | ||
* query which does that. | ||
*/ | ||
CREATE UNIQUE INDEX ON omicron.public.ip_pool_range ( | ||
first_address | ||
) | ||
STORING (last_address) | ||
WHERE time_deleted IS NULL; | ||
CREATE UNIQUE INDEX ON omicron.public.ip_pool_range ( | ||
last_address | ||
) | ||
STORING (first_address) | ||
WHERE time_deleted IS NULL; | ||
|
||
/*******************************************************************/ | ||
|
||
/* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
||
//! IP Pools, collections of external IP addresses for guest instances | ||
|
||
use crate::authz; | ||
use crate::context::OpContext; | ||
use crate::db; | ||
use crate::db::lookup::LookupPath; | ||
use crate::db::model::Name; | ||
use crate::external_api::params; | ||
use crate::external_api::shared::IpRange; | ||
use ipnetwork::IpNetwork; | ||
use omicron_common::api::external::CreateResult; | ||
use omicron_common::api::external::DataPageParams; | ||
use omicron_common::api::external::DeleteResult; | ||
use omicron_common::api::external::ListResultVec; | ||
use omicron_common::api::external::LookupResult; | ||
use omicron_common::api::external::UpdateResult; | ||
use uuid::Uuid; | ||
|
||
impl super::Nexus { | ||
pub async fn ip_pool_create( | ||
&self, | ||
opctx: &OpContext, | ||
new_pool: ¶ms::IpPoolCreate, | ||
) -> CreateResult<db::model::IpPool> { | ||
self.db_datastore.ip_pool_create(opctx, new_pool).await | ||
} | ||
|
||
pub async fn ip_pools_list_by_name( | ||
&self, | ||
opctx: &OpContext, | ||
pagparams: &DataPageParams<'_, Name>, | ||
) -> ListResultVec<db::model::IpPool> { | ||
self.db_datastore.ip_pools_list_by_name(opctx, pagparams).await | ||
} | ||
|
||
pub async fn ip_pools_list_by_id( | ||
&self, | ||
opctx: &OpContext, | ||
pagparams: &DataPageParams<'_, Uuid>, | ||
) -> ListResultVec<db::model::IpPool> { | ||
self.db_datastore.ip_pools_list_by_id(opctx, pagparams).await | ||
} | ||
|
||
pub async fn ip_pool_fetch( | ||
&self, | ||
opctx: &OpContext, | ||
pool_name: &Name, | ||
) -> LookupResult<db::model::IpPool> { | ||
let (.., db_pool) = LookupPath::new(opctx, &self.db_datastore) | ||
.ip_pool_name(pool_name) | ||
.fetch() | ||
.await?; | ||
Ok(db_pool) | ||
} | ||
|
||
pub async fn ip_pool_delete( | ||
&self, | ||
opctx: &OpContext, | ||
pool_name: &Name, | ||
) -> DeleteResult { | ||
let (.., authz_pool, db_pool) = | ||
LookupPath::new(opctx, &self.db_datastore) | ||
.ip_pool_name(pool_name) | ||
.fetch_for(authz::Action::Delete) | ||
.await?; | ||
self.db_datastore.ip_pool_delete(opctx, &authz_pool, &db_pool).await | ||
} | ||
|
||
pub async fn ip_pool_update( | ||
&self, | ||
opctx: &OpContext, | ||
pool_name: &Name, | ||
updates: ¶ms::IpPoolUpdate, | ||
) -> UpdateResult<db::model::IpPool> { | ||
let (.., authz_pool) = LookupPath::new(opctx, &self.db_datastore) | ||
.ip_pool_name(pool_name) | ||
.lookup_for(authz::Action::Modify) | ||
.await?; | ||
self.db_datastore | ||
.ip_pool_update(opctx, &authz_pool, updates.clone().into()) | ||
.await | ||
} | ||
|
||
pub async fn ip_pool_list_ranges( | ||
&self, | ||
opctx: &OpContext, | ||
pool_name: &Name, | ||
pagparams: &DataPageParams<'_, IpNetwork>, | ||
) -> ListResultVec<db::model::IpPoolRange> { | ||
let (.., authz_pool) = LookupPath::new(opctx, &self.db_datastore) | ||
.ip_pool_name(pool_name) | ||
.lookup_for(authz::Action::ListChildren) | ||
.await?; | ||
self.db_datastore | ||
.ip_pool_list_ranges(opctx, &authz_pool, pagparams) | ||
.await | ||
} | ||
|
||
pub async fn ip_pool_add_range( | ||
&self, | ||
opctx: &OpContext, | ||
pool_name: &Name, | ||
range: &IpRange, | ||
) -> UpdateResult<db::model::IpPoolRange> { | ||
let (.., authz_pool) = LookupPath::new(opctx, &self.db_datastore) | ||
.ip_pool_name(pool_name) | ||
.lookup_for(authz::Action::Modify) | ||
.await?; | ||
self.db_datastore.ip_pool_add_range(opctx, &authz_pool, range).await | ||
} | ||
|
||
pub async fn ip_pool_delete_range( | ||
&self, | ||
opctx: &OpContext, | ||
pool_name: &Name, | ||
range: &IpRange, | ||
) -> DeleteResult { | ||
let (.., authz_pool) = LookupPath::new(opctx, &self.db_datastore) | ||
.ip_pool_name(pool_name) | ||
.lookup_for(authz::Action::Modify) | ||
.await?; | ||
self.db_datastore.ip_pool_delete_range(opctx, &authz_pool, range).await | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.