Repository navigation
Allow DNS on VPC tiers (override) and make VPC DNS updatable via updateVPC #14168
Description
As a user of VPCs I would like to set custom DNS servers on an individual VPC tier, with the VPC's DNS as the default when a tier has none, and I would like to change a VPC's DNS after creation via updateVPC. Today both are refused, while isolated networks already support both, and the VPC virtual router already renders DNS per tier interface.
Current behaviour (4.22.1.1, verified against a live install and source)
| Call | Result |
|---|---|
createVPC with dns1/dns2 |
accepted; tiers created afterwards inherit the values (since #8621) |
createNetwork with vpcid + dns1/dns2 |
refused: DNS can not be specified for a VPC tier |
updateNetwork on a tier + dns1/dns2 |
refused with the same message, asynchronously (job fails) |
updateVPC + dns1/dns2 |
parameters do not exist; the values are ignored and the VPC keeps its original DNS |
updateNetwork on an isolated network + dns1/dns2 |
accepted; the row is updated and the network is restarted to re-render the VR |
Why this looks like an oversight rather than a design limit
-
The feature's own PR says tiers were in scope. api,server: custom dns for guest network #6425 (4.18) describes itself as adding custom DNS "for isolated network, shared network and VPC tier", and its Marvin test is named
test_network_vpc_custom_dns.py. The refusal for tiers has nonetheless been present since 4.18.0.0. I could not find a review comment on api,server: custom dns for guest network #6425 explaining the exclusion. -
The refusal is a single unconditional check, not a setting or an offering capability.
NetworkServiceImpl.checkNetworkDns:if (vpcId != null) { throw new InvalidParameterValueException("DNS can not be specified for a VPC tier"); }
It is reached from both
createNetworkand, viacheckAndUpdateNetworkDns, fromupdateNetwork. -
Everything downstream of the check already handles per-tier DNS:
- Tier networks are rows in the same
networkstable as isolated networks, with the samedns1/dns2/ip6_dns1/ip6_dns2columns. Since vpc: create vpc tiers with dns server of vpc instead of zone #8621 the VPC's values are written into each tier row at create. NetworkModelImpl.getNetworkIp4Dnsresolves network row → VPC → zone, so a tier with its own value already takes precedence over the VPC value.CommandSetupHelperpasses the resolved DNS to the VR per guest network, and the VR renders onedhcp-option=tag:interface-ethN,6,...line per tier interface. The dnsmasq config pasted in vpc: create vpc tiers with dns server of vpc instead of zone #8621 shows three tiers of one VPC with two different resolver lists.checkAndUpdateNetworkDnsalready diffs, writes the row and flags a restart; for a tier it only fails because it calls the same check.
For the tier half, the change appears to be: remove the
vpcId != nullbranch, expose the fields in the UI's tier forms, and confirm that a (non-cleanup) tier restart re-renders the tier's dnsmasq options. I have not verified that last point. - Tier networks are rows in the same
What is genuinely missing (the VPC half)
updateVPChas nodns1/dns2/ip6dns1/ip6dns2parameters.- Because vpc: create vpc tiers with dns server of vpc instead of zone #8621 copies the VPC's DNS into each tier row at create, a later VPC change cannot tell a tier that inherited the value from one that set the same value explicitly. A cascade needs an "inherit" representation, for example NULL on the tier meaning "follow the VPC", with
getNetworkIp4Dnsalready providing the fallback. That is a small design decision rather than a guard removal, and the reason I am filing this as a request rather than a PR.
Proposed behaviour
createNetwork/updateNetworkon a VPC tier acceptdns1/dns2(and the IPv6 pair where the tier is IPv6-enabled), subject to the offering carrying theDnsservice exactly as isolated networks are.- A tier with no DNS of its own follows the VPC; a tier with DNS set keeps its own.
updateVPCacceptsdns1/dns2/ip6dns1/ip6dns2; tiers that follow the VPC pick up the change; the change is applied to running routers on VPC restart, as the isolated-network update does today.- Semantics as for isolated networks: the new values reach guests on their next DHCP lease, so running guests see them after a renew or reboot.
Question for maintainers
If the tier refusal exists to protect a configuration where tiers are not served by the VPC VR (for example NSX or Netris backed VPCs), then the request is to narrow the check to those providers rather than to all VPCs.
Versions checked: 4.18.0.0, 4.19.0.0, 4.22.1.1, 4.23.0.0 (the check is identical in all four).
Related: #6425 (adds custom DNS, 4.18), #8598 / #8621 (tiers inherit VPC DNS, 4.19).
Activity
boring-cyborg commentedon Sep 15, 2026
Thanks for opening your first issue here! Be sure to follow the issue template!
github-actions commentedon Sep 15, 2026
🎯 Triage report
This request asks that VPC tiers be allowed to set custom DNS (currently refused by an unconditional check in
NetworkServiceImpl.checkNetworkDns) and thatupdateVPCgaindns1/dns2/ip6dns1/ip6dns2parameters. The author provides detailed code references and a behavior matrix across multiple versions (4.18–4.23), and raises an open question for maintainers about whether the current restriction is intentional for non-VR-backed VPCs (e.g., NSX/Netris).📊 Assessment
type:enhancementcomponent:vpc,component:networkingupdateVPCrequire a design decision (e.g., NULL-as-inherit) and confirmation of behavior for non-VR-backed VPCs (NSX/Netris) before implementation can safely proceed.🔗 Similar issues
No similar or duplicate open issues found via search. Related closed/merged work referenced by the author: #6425, #8598, #8621.
💡 Notes and suggestions
vpcId != nullguard incheckNetworkDnswas an intentional restriction for VPC implementations without VR-managed DNS (NSX/Netris), as the author suggests narrowing the check to those providers only.updateVPCparameter addition could be split into two smaller, separately reviewable changes.Add this agentic workflows to your repo
To install this agentic workflow, run
skorchir commentedon Sep 17, 2026
Both questions checked at tag 4.22.1.1.
On the NSX/Netris question
The dates rule intent out. The guard arrived in #6425, merged 2022-09-10 for 4.18.0.0; the NSX plugin landed 2024-03-08 (#7919, 4.20.0) and Netris 2025-07-25 (#10458, 4.21.0).
checkNetworkDnsis textually unchanged since that merge (NetworkServiceImpl.java:651).Neither plugin serves DNS anyway. Neither plugin tree reads a network's DNS fields at all. NSX points a DHCP relay at the VPC VR's tier NIC (
NsxGuestNetworkGuru.java:244-248); Netris disables DHCP on every vnet gateway it creates (NetrisApiClientImpl.java:1890). Both elements implementDhcpServiceProvider/DnsServiceProviderasreturn trueno-ops, and the shipped default offerings map Dhcp/Dns/UserData toVPCVirtualRouter(ConfigurationServerImpl.java:1256,VpcManagerImpl.java:440). On both, the VPC VR is the DNS server.Nothing forces that mapping for an admin-created NSX/Netris offering, so I would narrow rather than delete: refuse only when the tier's Dns provider is not the VR, using the helper the render path already asks —
isProviderSupportServiceInNetwork(network.getId(), Service.Dns, Provider.VPCVirtualRouter)(CommandSetupHelper.java:1199). At create there is no network id yet, so the offering's service→provider map is the equivalent; the offering check atNetworkServiceImpl.java:660is currently dead for tiers because thevpcIdthrow precedes it.On inherit-vs-explicit
A correction to my report first: nothing copies the VPC's DNS onto a tier row at create. #8621 (4.19.1.0) added a read-time fallback only, and tier rows are NULL by construction because of the guard.
getNetworkIp4Dns/getNetworkIp6Dnsalready resolve row → VPC → zone (NetworkModelImpl.java:2750and:2764), so NULL already means "follow the VPC" on every render path I traced.One row-direct reader is harmless:
NetworkOrchestrator.updateRouterDefaultDns(:464) reads the VPC row for a VPC router, never a tier. The problem isapplyProfileToNetwork(NetworkOrchestrator.java:1389), which persists the resolved dns1/dns2 back onto the network row on every successfulshutdownNetwork(:3241). GC reaches it when the last VM leaves a tier on a non-persistent offering (NetworkDaoImpl.findNetworksToGarbageCollect,:540-547), baking the VPC's or zone's IPv4 into the row; ip6 is not written, so the two families diverge.Proposed design:
applyProfileToNetwork: the profile value is already the resolved row → VPC → zone answer, recomputed on every render, so the write-back adds nothing and only collapses the NULL. If dropping it outright is too broad, skip the write when the row's dns1 was NULL going in.UpdateVPCCmd(six today, none DNS) plus acheckVpcDnscall on the update path, and cascade by re-rendering tiers whose DNS is NULL. A no-cleanup tier restart sends noSetupGuestNetworkCommandonce the router is attached (VpcVirtualRouterElement.java:253), and cleanup restart is refused on a tier, so the cascade has to run through the whole-VPC restart (VpcManagerImpl.java:2454).I traced the bake statically only and could not say how often it fires in practice.
As the triage note suggests, the guard narrowing and the updateVPC cascade are independent and could land as two PRs.
DaanHoogland commentedon Sep 30, 2026
@sudo87 can you add your opinion on this?
zenbiking commentedon Oct 20, 2026
If we had a need or desire to work around this issue, would editing the values for dns1 and dns2 directly in the database be the approach to take? I'm normally not a fan of making such changes, but in my limited testing his appears to work as intended.