feat(network): apply richer IPAM at network creation time#15
Draft
chrisgeo wants to merge 1 commit into
Draft
Conversation
Extends `container network create` and the `container-network-vmnet` plugin to honor six compose-spec / Docker-style network creation options that were previously silently dropped: `--gateway`, `--ip-range`, `--aux-address`, `--driver-opt`, `--ipv6`, and `--attachable`. The vmnet plugin now actually wires the user's gateway override and IPv4 sub-range constraints through to the runtime; aux-address reservations are pre-allocated in the per-network attachment allocator so the dynamic pool never hands them out. Motivation ---------- Container-Compose (and other compose-spec orchestrators) decode these fields from `docker-compose.yml` but cannot apply them today because `container network create` only accepts `--label`, `--internal`, `--subnet`, `--subnet-v6`, `--plugin`, and `--plugin-variant`. The gap was tracked downstream in CHAOS-1334 and surfaced as warn-and-skip behaviour in container-compose's `setupNetwork` path. With this PR the runtime accepts the full IPAM surface and the plugin honours each field at network start. What this PR changes -------------------- - Sources/ContainerResource/Network/NetworkConfiguration.swift: six new optional fields on the persisted `NetworkConfiguration` (`ipv4Gateway`, `ipv4Range`, `auxAddresses`, `driverOpts`, `attachable`, `enableIPv6`). All decoded with `decodeIfPresent`, encoded with `encodeIfPresent`, and validated end-to-end (gateway, range, and aux-addresses must lie inside `ipv4Subnet` when both are configured). - Sources/ContainerCommands/Network/NetworkCreate.swift: matching CLI flags (`--gateway`, `--ip-range`, `--aux-address HOSTNAME=IP` repeatable, `--driver-opt KEY=VALUE` repeatable, `--ipv6`, and `--attachable`). The CLI emits an explicit advisory on stderr when `--attachable` is requested because apple/container has no swarm attachment concept. - Sources/Services/ContainerAPIService/Server/Networks/NetworksService.swift: `registerService` now serializes the new configuration fields into argv passed to the plugin's `start` subcommand. `auxAddresses` is encoded as a single JSON argv value to keep the wire shape simple and trivially extensible; `driverOpts` is forwarded as repeated `--driver-opt KEY=VALUE` entries. - Sources/Plugins/NetworkVmnet/NetworkVmnetHelper+Start.swift: parses the new argv (`--gateway`, `--ip-range`, `--aux-addresses`, `--driver-opt`, `--ipv6`) and reconstructs a richer `NetworkConfiguration` for the vmnet variants. - Sources/Services/ContainerNetworkService/Server/ReservedVmnetNetwork.swift and AllocationOnlyVmnetNetwork.swift: the IPv4 gateway is no longer hard-coded to `subnet.lower + 1`. When the configuration carries an explicit `ipv4Gateway`, that address is passed directly to `vmnet_network_configuration_set_ipv4_subnet` and validated as in-subnet. The allocation-only variant explicitly rejects the IPv6 request paths with an actionable error pointing users at the `reserved` variant on macOS 26+. - Sources/Services/ContainerNetworkService/Server/NetworkService.swift: the per-network attachment allocator now accepts an `ipv4Range` override (so the dynamic pool spans the user-supplied sub-CIDR rather than the full subnet) and pre-reserves both a custom gateway and any in-range `auxAddresses` through `RotatingAddressAllocator`'s existing `reserve(_:)` API. Out-of-range aux entries are recorded for reference but require no allocator state because they are already outside the dynamic pool. - Sources/Services/ContainerNetworkService/Server/AttachmentAllocator.swift: small `reserveHostname(hostname:address:)` helper that wraps the underlying allocator's `reserve(_:)` with the actor's hostname-to-index dictionary, so reserved entries round-trip through `lookup` / `deallocate`. Wire compatibility ------------------ All new `NetworkConfiguration` fields are optional and decoded with `decodeIfPresent`; configurations persisted by older daemons decode cleanly with `nil` defaults (covered by the `testLegacyConfigurationDecodesWithoutNewFields` regression test). Plugin argv is purely additive: a newer `NetworksService` against an older plugin will pass argv that the plugin ignores; an older `NetworksService` against a newer plugin simply omits the new flags and the plugin behaves as before. Known limitations (intentional, follow-up work) ----------------------------------------------- - `--attachable` is accepted at the CLI for compose-spec parity but is not threaded into the plugin and produces no behavioural change on apple/container, which has no swarm-mode attachment concept. The CLI surfaces this explicitly on stderr. - `--driver-opt KEY=VALUE` is parsed, persisted on the configuration, and forwarded through to the plugin process, but the vmnet plugin does not currently interpret any specific keys. Keeping the surface on day one means future plugin enhancements can interpret options (e.g. DHCP toggles) without another wire-format break. - Bare `--ipv6` (no `--subnet-v6`) takes effect on the `reserved` variant only; the `allocation-only` variant does not yet support IPv6 and now emits an actionable error pointing at the `reserved` variant on macOS 26+. - The IPv4 gateway override only takes effect when an explicit `--subnet` is also supplied; without a subnet, vmnet is the source of truth for both subnet and gateway. Verification ------------ - `swift build -c release` clean on macOS 26 / Apple silicon. - `swift test --filter ContainerResourceTests.NetworkConfigurationTest` passes 11 tests (3 pre-existing + 8 new), covering: gateway/range/ aux-address validation (positive and negative), full-shape Codable round-trip, and decoding a legacy (pre-PR) JSON configuration with none of the new fields populated.
237a1b4 to
a8150c8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends
container network createand thecontainer-network-vmnetplugin to honor six compose-spec / Docker-style network creation options that were previously silently dropped:--gateway,--ip-range,--aux-address,--driver-opt,--ipv6, and--attachable.The vmnet plugin actually wires the user's gateway override and IPv4 sub-range constraints through to the runtime; aux-address reservations are pre-allocated in the per-network attachment allocator so the dynamic pool never hands them out.
This is the upstream-shaped staging PR for CHAOS-1334 (Container-Compose). Companion downstream PR will land after this is reviewed.
CLI surface
--gateway <IPv4>vmnet_network_configuration_set_ipv4_subnet's gateway parameter (Reserved + AllocationOnly variants)subnet.lower + 1. Requires--subnet.--ip-range <CIDRv4>AttachmentAllocatorlower/size bounds--subnet.--aux-address HOSTNAME=IPRotatingAddressAllocator.reserve(_:)pre-reservation--driver-opt KEY=VALUENetworkConfigurationand forwarded to plugin argv--ipv6(bare)reservedvariant on macOS 26+.--attachableWhat changed
Sources/ContainerResource/Network/NetworkConfiguration.swift— six new optional fields withdecodeIfPresent/encodeIfPresentCodable plumbing and end-to-end validation.Sources/ContainerCommands/Network/NetworkCreate.swift— matching CLI flags.Sources/Services/ContainerAPIService/Server/Networks/NetworksService.swift—registerServiceserializes the new fields into plugin start argv (JSON for the aux-address dict; repeated--driver-optfor opts).Sources/Plugins/NetworkVmnet/NetworkVmnetHelper+Start.swift— parses the new argv and reconstructs the richerNetworkConfiguration.Sources/Services/ContainerNetworkService/Server/{Reserved,AllocationOnly}VmnetNetwork.swift— honor user-provided gateway; AllocationOnly explicitly rejects IPv6 requests.Sources/Services/ContainerNetworkService/Server/NetworkService.swift— allocator range respectsipv4Range; pre-reserves custom gateway + in-rangeauxAddresses.Sources/Services/ContainerNetworkService/Server/AttachmentAllocator.swift— newreserveHostname(hostname:address:)helper around the underlying allocator'sreserve(_:).Wire compatibility
All new
NetworkConfigurationfields are optional and decoded withdecodeIfPresent. Configurations persisted by older daemons decode cleanly withnildefaults (covered bytestLegacyConfigurationDecodesWithoutNewFields). Plugin argv is purely additive — newer server vs. older plugin and vice versa both behave correctly.Known limitations (intentional, follow-up work)
--attachableis parsed but produces no behavioural change on apple/container today. The CLI surfaces this explicitly on stderr.--driver-optis forwarded but the vmnet plugin interprets no specific keys yet.--ipv6is honored on thereservedvariant only; AllocationOnly emits an actionable error pointing at thereservedvariant on macOS 26+.--subnetis also supplied (vmnet is source of truth otherwise).Verification
swift build -c release— clean on macOS 26 / Apple silicon.swift test --filter ContainerResourceTests.NetworkConfigurationTest— 11/11 passing (3 pre-existing + 8 new). Coverage: gateway/range/aux-address positive + negative validation, full-shape Codable round-trip, legacy-config decode regression.