From 068bd4f5506664dca6ccf9fae886a2b643a741d1 Mon Sep 17 00:00:00 2001 From: Marco Sinhoreli Date: Wed, 29 Apr 2026 21:38:52 +0200 Subject: [PATCH] network: ConfigDrive must check Dhcp/Dns on the network, not on itself MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ConfigDriveNetworkElement.getSupportedServicesByElementForNetwork gates the population of network_data.json on the ConfigDrive provider declaring Dhcp and Dns services for the NIC's network. On any modern offering where ConfigDrive is bound only to UserData and Dhcp / Dns are delivered by a different provider — Ovn, Netris, Nsx, even VirtualRouter when the operator has split UserData out — this predicate returns false. ConfigDriveBuilder.writeNetworkData then honours the empty service list and writes `network_data.json = "{}"`. The ISO ends up with hostname and SSH keys (read from meta_data.json) but no `links` / `networks` / `services` for cloud-init. Older cloud-init releases used to fall back to a DHCP-everything heuristic; cloud-init >= 23 (shipped with Ubuntu 24.04 cloud images and current Debian 12 backports) does not, so the VM boots with whatever pre-baked netplan is in the image. For canonical cloud images that means no interface comes up at all, because their netplan is rendered from datasource at first boot — which is exactly the path we just defeated. The Dhcp / Dns checks should not be scoped to the ConfigDrive element; they should be scoped to the network, because the question is "does cloud-init need network configuration in the ISO?" not "does ConfigDrive itself implement Dhcp on this network?". Switch those two probes to areServicesSupportedInNetwork. UserData stays scoped to the ConfigDrive provider — that one IS implemented here. Lab-verified before / after on an OVN-backed isolated network whose offering is `Dhcp=Ovn / Dns=Ovn / UserData=ConfigDrive`: Before /openstack/latest/network_data.json = "{}" Ubuntu 24.04 cloud image: hostname/SSH keys applied via cloud-init, no interface up, VM unreachable. After /openstack/latest/network_data.json includes links[], networks[], services[] for the NIC. Ubuntu 24.04 cloud image: cloud-init renders netplan, DHCPv4 lease acquired on first boot, VM reachable on its DHCP-assigned IP. Affects every CloudStack deployment whose offering routes UserData to ConfigDrive while routing Dhcp/Dns to a separate provider — including all OVN-backed offerings, the Netris and NSX route-mode offerings, and any operator-built offering that decouples the two. The fix is a one-line predicate change inside core, nothing provider-specific. Co-Authored-By: Claude Opus 4.7 --- .../network/element/ConfigDriveNetworkElement.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java index 6cdd6f5753d7..1d9fc22b0290 100644 --- a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java +++ b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java @@ -631,13 +631,22 @@ private Map> getSupportedServicesByElementForNetwork Map> supportedServices = new HashMap<>(); for (NicProfile nic: nics) { ArrayList serviceList = new ArrayList<>(); - if (_networkModel.isProviderSupportServiceInNetwork(nic.getNetworkId(), Service.Dns, getProvider())) { + // Dhcp / Dns are checked against the network as a whole rather than against the + // ConfigDrive provider itself. Their actual provider on a modern offering can be + // a different element entirely (Ovn / Netris / Nsx / VirtualRouter ...), but the + // information cloud-init needs in network_data.json — link MTU, expected IPv4, + // gateway, DNS servers — must still be emitted on the ConfigDrive ISO. Without + // this, network_data.json is written as `{}` and Ubuntu 24.04 / cloud-init >= 23 + // does not bring any interface up at boot, even though hostname / SSH keys (read + // from meta_data.json) are correctly applied. UserData stays scoped to ConfigDrive + // because that one IS provided by this element directly. + if (_networkModel.areServicesSupportedInNetwork(nic.getNetworkId(), Service.Dns)) { serviceList.add(Service.Dns); } if (_networkModel.isProviderSupportServiceInNetwork(nic.getNetworkId(), Service.UserData, getProvider())) { serviceList.add(Service.UserData); } - if (_networkModel.isProviderSupportServiceInNetwork(nic.getNetworkId(), Service.Dhcp, getProvider())) { + if (_networkModel.areServicesSupportedInNetwork(nic.getNetworkId(), Service.Dhcp)) { serviceList.add(Service.Dhcp); } supportedServices.put(nic.getId(), serviceList);