-
Notifications
You must be signed in to change notification settings - Fork 40
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
Add IP Pools and contained IP ranges #1253
Conversation
- Adds basic CRUD API for IP Pools, as named, global resources - Adds table and database operations for IP Pools - Adds API for operating on IP ranges within an IP Pool. These are expressed as a first/last IP address pair, and describe a range of addresses to add or remove from a pool. Currently, all ranges must be non-overlapping, which is checked at insertion time with a custom query. Deleting a range currently requires specifying the exact same first/last address used to create it. Both of these could be relaxed in the future without changing the API, for example to support splitting or coalescing ranges. - Adds paginated endpoint for listing the ranges within a pool, ordered by the first address in the range. - Adds integration tests for new endpoints. - Adds unauthorized coverage checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, nice job getting this integrated!
* 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 comment
The 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 comment
The 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 network_interface
table.
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 ip_pool
table, for finding the ranges within that set. Specifically for IP Pools in the sense of instance NAT, I do expect that we'll update the network_interface
table (or add a new table) to include the IPs from this range that are currently in use. It all gets pretty hairy here in terms of the database operations, since now there are at least 3 tables to consider for certain operations, such as deleting an IP Pool resource.
- Constructors and getters for IP range types to ensure they are non-decreasing - Tests of IP range types - Better conversions between model / view / public IP range types - Remove lots of dead code, some comment cleanup - Rename some types to avoid OpenAPI confusion
Thanks for fixing the OpenAPI schema thing. Running this through the TS generator, there's no way to distinguish between IPv4 and IPv6 because of TS's structural typing. Usually we use a discriminator property to discriminate, like adding |
@david-crespo Sure thing, thanks for flagging it. What does the TS generator do for |
😁 type IpNet = Ipv4Net | Ipv6Net
type Ipv4Net = string
type Ipv6Net = string So far it has not been a problem. I'll keep an eye on it. We also pull in the regex pattern for validating each one at runtime, but the types don't know anything about that. |
Welp, that's a bummer 😆 . We can make them internally-tagged, e.g., the type/value keys that you referred to earlier. I don't really have a horse in the race -- it's all the same once we deserialize into Rust, so whatever makes the clients work better. @ahl Any suggestions here? |
As I recall, we drew inspiration from And the For omicron/common/src/api/external/mod.rs Lines 1206 to 1232 in 3690806
As an aside, progenitor recovers the the type pretty well, but doesn't properly include the custom regex for deserialization: #[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum IpNet {
V4(Ipv4Net),
V6(Ipv6Net),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Ipv4Net(pub String); Part of the motivation here is to let consumers of the API simply say: {
"ip": "127.0.0.1"
} Rather than {
"ip": {
"v4": "127.0.0.1"
}
} ... or something like that. I think ideally a generator is going to either distinguish types based on these regexes or do a "deep collapse" i.e. saying
should be collapsed into
So either we should:
|
Also for context (at least for myself): |
From TS's POV it is already collapsed because the following are equivalent: type X = { first: string; last: string } | { first: string; last: string }
type Y = { first: string, last: string } |
Thanks Adam, that's helpful. I would argue we don't use the regular expressions for determining types. There has already been at least one bug, and I'm betting there are more. The server will ultimately parse the request data anyway, rather than validate they match the regex, so those errors will just be annoying for clients. One option here is to not have an enum, but use a generic (@davepacheco proposed this above). For the range, it'd be something like |
- Move IpRange types to shared Nexus crate - Remove more dead code - Cleanup some comments
- Remove unnecessary pagination order from ip pool ranges - Remove more dead code - Untagged enum repr for IpRange type
@smklein @davepacheco @david-crespo Thanks all for the helpful input! Let me know if y'all have any further comments. |
Propolis changes: Update h2 dependency Add NPT ops API definitions from illumos#15639 server: return better HTTP errors when not ensured (#649) Crucible changes: Make Region test suite generic across backends (#1263) Remove async from now-synchronous functions (#1264) Agent update to support cloning. (#1262) Remove the Active → Faulted transition (#1260) Avoid race condition in crutest rand-read/write (#1261) Add Active -> Offline -> Faulted tests (#1257) Reorganize dummy downstairs tests (#1253) Switch to unbounded queues (#1256) Add Upstairs session ID to dtrace stat probe, cleanup closure (#1254) Panic instead of returning errors in unit tests (#1251) Add a clone option to downstairs create (#1249)
Propolis changes: Update h2 dependency Add NPT ops API definitions from illumos#15639 server: return better HTTP errors when not ensured (#649) Crucible changes: Make Region test suite generic across backends (#1263) Remove async from now-synchronous functions (#1264) Agent update to support cloning. (#1262) Remove the Active → Faulted transition (#1260) Avoid race condition in crutest rand-read/write (#1261) Add Active -> Offline -> Faulted tests (#1257) Reorganize dummy downstairs tests (#1253) Switch to unbounded queues (#1256) Add Upstairs session ID to dtrace stat probe, cleanup closure (#1254) Panic instead of returning errors in unit tests (#1251) Add a clone option to downstairs create (#1249) Co-authored-by: Alan Hanson <alan@oxide.computer>
expressed as a first/last IP address pair, and describe a range of
addresses to add or remove from a pool. Currently, all ranges must be
non-overlapping, which is checked at insertion time with a custom
query. Deleting a range currently requires specifying the exact same
first/last address used to create it. Both of these could be relaxed
in the future without changing the API, for example to support
splitting or coalescing ranges.
by the first address in the range.