WIP PE-9376: ship a default DHCP networkd config for physical NICs in the SLE Micro 5.5 image - #811
Draft
kirankn8 wants to merge 1 commit into
Draft
WIP PE-9376: ship a default DHCP networkd config for physical NICs in the SLE Micro 5.5 image#811kirankn8 wants to merge 1 commit into
kirankn8 wants to merge 1 commit into
Conversation
kairos-init disables NetworkManager on SLE Micro and enables systemd-networkd,
but no CanvOS image ships a .network for physical interfaces -- the only writer
is the runtime yip stage /system/oem/05_network.yaml. When that stage does not
take effect the host boots with networkd running and zero configuration, leaving
every NIC unmanaged, wait-online failing and sshd down.
Ship the same 20-dhcp{,-legacy}.network the stage would write, under
/usr/lib/systemd/network so it is part of the read-only image and cannot be
masked by the persistent /etc/systemd bind mount. The 20- prefix keeps it losing
to the 05-/10-/15- files Stylus writes from site user-data.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Problem
A host installed from the SLE Micro 5.5 installer boots to multi-user with no network: all physical NICs down and
unmanaged,/etc/systemd/network/empty,systemd-networkdactive, NetworkManager and wicked inactive,systemd-networkd-wait-online.servicefailing andsshdfailing in a loop. No IP, no registration, console only.Root cause
Confirmed against the real images, not inferred:
No CanvOS image ever ships a
.networkfor physical NICs.kairos-initwrites none at build time for any flavour. Verified directly:/etc/systemd/network/is empty inkairos-slem:5.4-core-amd64-generic-v0.17.1, and/usr/lib/systemd/network/inregistry.suse.com/suse/sle-micro/5.5:latestholds only99-default.linkplus container/VM/wifi units — nothing matching physical ethernet. This matches the reported state exactly.The only thing that ever creates
20-dhcp.networkis a runtime yip stage,/system/oem/05_network.yaml(rootfs.beforeandinitramfs). Every flavour depends on it — it is a single point of failure at boot.SLE Micro is the only flavour where that failure is fatal.
kairos-initpkg/stages/steps_init.go:513-521(OnlyMicroRegex) doessystemctl disable NetworkManager, and:523-534enablessystemd-networkd/systemd-resolved/sshd. Verified:NetworkManager.serviceis present inmulti-user.target.wantsin the SLE Micro base image and absent afterkairos-init. On RHEL,kairos-initre-enables NetworkManager when the binary is present (steps_init.go:596), so a missed stage is survivable there. On SLE Micro nothing is left to bring the NICs up.slem/5.5/Dockerfiledoes not compensate. Unlikerhel-core-images/Dockerfile.rhel9:87-89andubuntu-kairos-base/Dockerfile:248-249, it had no networking or unit-enablement step at all.Ruled out
The ticket suggested the generated config might reference the wrong NIC names. It does not, and neither of the obvious suspects holds:
only_osregex mismatch — ruled out. yip matches the regex againstPRETTY_NAME, notNAME(yip/pkg/plugins/if_os.go:31→sysinfo.OS.Name;zcalusic/sysinfo/os.go:50). SLE Micro'sPRETTY_NAMEis"SUSE Linux Enterprise Micro for Rancher 5.5", which matchesSUSE.*. Verified empirically by runningkairos-agent run-stage initramfswith each flavour'sPRETTY_NAME: Ubuntu 22.04/24.04, RHEL 8/9, openSUSE Leap 15.6 and SLE Micro for Rancher 5.4/5.5 all produce both files. Only aNAME-style"SLE Micro 5.5"fails to match.05_network.yamlmissing or altered in the slem image — ruled out. Present inkairos-slem:5.4, byte-identical to the Ubuntu image's copy (2980 bytes,diffclean). Nothing inEarthfileorslem/5.5/Dockerfileremoves it (therm -f /system/oem/*_elemental-*glob does not match it).systemd-networkd,systemd-resolvedandsshdare allenabledin the built slem base.What I could not determine from the artifacts available to me is which runtime failure mode stopped the stage from taking effect on that specific host — I had no access to the box and cannot build the image (see Verification). Candidates include the
/etc/systemdpersistent bind (immucore rsyncs with-u, so a stale state copy pins forever) andOpMountBindbeing skipped whenOpOverlayMountfails. This change makes that question moot: it removes the dependency on the runtime stage entirely.The change
Ship the same DHCP default the yip stage would write, baked into the image:
slem/5.5/overlay/usr/lib/systemd/network/20-dhcp.network—[Match] Name=en*,[Network] DHCP=yesslem/5.5/overlay/usr/lib/systemd/network/20-dhcp-legacy.network—[Match] Name=eth*slem/5.5/Dockerfile:COPY overlay/ /afterkairos-init(same idiom asrhel-core-images), plus an assertion that the networkd binary exists and the three units are enabled —kairos-initenables networkd for SLE Micro without thetest -fguard the RHEL branch has, and the binary only arrives via an openSUSE Leap OSS repo whose signing key this Dockerfile already documents as expired. Better to fail the build than ship an image with no network stack.Content is byte-identical to what upstream writes, so behaviour matches every other flavour.
Both layers
slem/5.5/DockerfileproducesBASE_IMAGE, consumed byEarthfile:940+base-image, which is the ancestor of both+iso-image(installer/live squashfs,Earthfile:1234) and+provider-image(installed root,Earthfile:733)./usris read-only image content in both. Verified in the built image:/usr/lib/systemd/network/20-dhcp.networkand20-dhcp-legacy.networkpresent with the expected content;/etc/systemd/network/still empty (we clobber nothing).Why
/usr/liband not/etc/usris never overlaid, bind-mounted or made writable by immucore — the only/usrpaths it touches are/usr/local(the COS_PERSISTENT mountpoint) and/usr/local/.state. So the file is byte-for-byte the image's, on every boot, in live and installed mode alike./etc/systemdis different: it is inPERSISTENT_STATE_PATHS(00_rootfs.yaml), and immucore rsyncs it into/usr/local/.state/etc-systemd.bindwithrsync -aquAX(immucore/internal/utils/mounts.go:95-106). The-umeans a state copy that is newer on the receiver is never overwritten, and there is no--delete, so an/etc-based default would be pinned on first boot and could never be corrected or retracted by a later image.How precedence is guaranteed
systemd-networkd merges
/etc,/runand/usr/liband applies the first matching.networkin lexicographic order by filename. Stylus writes, all into/etc/systemd/network/:.netdev05-<bond>.netdevpkg/network/network_networkd.go:66410-<iface>.networknetwork_networkd.go:493,:714,:36310-<selected>.networknetwork_networkd.go:78215-<member>.networkbridge_service.go:74920-dhcp{,-legacy}.networkdomain/constants.go:368-369Every file Stylus writes sorts before
20-, so user-data always wins. This is checked by test, not asserted: a Stylus-style/etc/systemd/network/10-enp2s0.networkwith a static address takesenp2s0and the address is applied, while unlisted NICs keep DHCP.The
20-dhcpnames are deliberate rather than arbitrary — a higher number would have broken Stylus.network_networkd.go:762-783renames20-dhcp.networkby that exact name when Palette selects a management NIC, andcmd/init-upgrade/main.go:252-292reads/etc/systemd/network/20-dhcp{,-legacy}.networkoff disk to pin it across an A/B upgrade. A99-file would be invisible to both. Same-name masking also means that if the runtime stage does write/etc/systemd/network/20-dhcp.network, it takes precedence over ours cleanly, with no duplicate-match conflict — verified by test.User-data path checked:
user-data.template:30-52(stylus.site.network.interfaces.<iface>.{type,ipAddress,gateway,nameserver}), applied by stylus as a yipinitramfsstage (pkg/service-handler/provider/event_handler.go:248) or synchronously atstylus.initduring registration (:327-359). With nonetwork:block stylus writes nothing at all (network_networkd.go:150-160) and the OS default is what applies — which is precisely the contractuser-data.template:40documents: "If omitted all interfaces will default to dhcp".Multi-NIC behaviour (3-NIC host)
Name=en*matches all three, soenp1s0/enp2s0/enp3s0are each managed and each runs an independent DHCP client — the files never fight over "which one is management", because they express no opinion about it. Management selection stays where it already lives:stylus.site.network.managementInterface.namebinds the local UI, and Palette's per-hostNic.NicNamedrivesselectedInterfaceName; both act via10-files that outrank this default. A NIC with no DHCP server simply gets no lease, exactly as on every other flavour. Verified: three NICs, three distinct subnets, three leases,wait-onlinereturns 0.Behaviour is unchanged for
loand for container/VM links (vz-*,ve-*,host0,vt-*) — they stayunmanaged, checked by test.Tests
New
test/test-slem-network-defaults.sh— runs the shipped files against a realsystemd-networkdon a three-NIC host, withvethpairs whose peers are served by the same networkd acting as a DHCP server, so leases are real. 17 checks:enp*reportunmanagedconfigured, each holding a lease from its own subnet,systemd-networkd-wait-onlinereturns 0en*→20-dhcp.network,eth*→20-dhcp-legacy.network,loandvz-*untouched10-<iface>.networkstatic config wins and its address is applied; unlisted NICs keep DHCP/etcfile of the same name masks the/usr/libdefault and its settings are the ones appliedAll 17 pass.
Cortex review
Breadth —
coupled_files(spectrocloud/CanvOS, slem/5.5/Dockerfile), 26 changes, population 539. Every partner disposed of:rhel-core-images/Dockerfile.rhel8kairos-init steps_init.go:596), so a missed yip stage is not fatal there.rhel-fips/Dockerfile.rhel8ubuntu-fips/20.04/Dockerfile(sibling_variant)PRETTY_NAME="Ubuntu 22.04/24.04"; flavour not reported broken.rhel-core-images/Dockerfile.rhel9PRETTY_NAME.rhel-fips/Dockerfile.rhel9rhel-core-images/Dockerfile.rhel9.sat.satvariants do not even COPY the overlay.rhel-core-images/Dockerfile.rhel8.satubuntu-fips/22.04/Dockerfile.ubuntu22.04-fipsrhel-stig/Dockerfile.rhel9rhel-stig/Dockerfile.rhel9-fipsslem/5.4/README.mdslem/5.5/build.shdocker buildwrapper, unaffected.ubuntu-fips/24.04/Dockerfile.ubuntu24.04-fipsubuntu-kairos-base/Dockerfileinformative: false, STALE 476d.rhel-fips/dracut.confinformative: false.coupled_directories(slem/5.5)addsrhel-core-images0.807/20,rhel-fips0.768/20,ubuntu-fips/20.040.742/20 (same dispositions) andslem/5.40.618/4 — see the flag below.Flagged, deliberately not changed: the CI-published slem base is
slem-5.4, and it is built fromregistry.suse.com/suse/sle-micro-rancher/5.4throughdockerfiles/kairosify/Dockerfile.kairosify(.github/workflows/base-images.yaml:124-134) — not throughslem/5.4/Dockerfileorslem/5.5/Dockerfile, neither of which is referenced byEarthfileor CI at all.slem/5.5is a hand-run path (slem/5.5/build.sh), which is what the reported installer was built from, so the fix is in the right place for this ticket. But I confirmedkairos-slem:5.4carries the identical exposure (empty/etc/systemd/network, NetworkManager not enabled). Extending the fix to the kairosify builder would touch the file that builds every flavour and I have no way to verify it here — calling that out for a maintainer decision rather than changing it blind.Depth —
upstream_repos(spectrocloud/CanvOS): "Nothing validated upstream. 1 discovery-tier edge withheld. This repository declares no internal dependencies."coupling_chain(upstream): no chains, "there was nothing to walk" — not evidence of absence.So Cortex offers no validated upstream edge. By code reading the defect does originate upstream, in
kairos-io/kairos-init: the SLE Micro branch turns off the working network stack and enables an unconfigured one, and no version throughmainfixes it (v0.17.3changes only sshd hardening/CI/deps;mainis byte-identical onvalues.go:201-206,packagemaps.go:552andsteps_init.go:488-534, and the repo now carries an archive notice pending migration intokairos-io/kairos).kairos-iois outside Cortex'sspectrocloudcoverage, so its silence here says nothing — the upstream conclusion is from reading the code, not from Cortex.The upstream-shaped fix would be to write the
.networkat build time in theOnlyMicroRegexbranch, or to guard the networkd enable withtest -fthe way the RHEL branch does. That is out of scope for this repo and the repo is being archived. Shipping the config in our own OS image is not merely a symptom patch: an OS image is the right place for its own default network configuration, and doing it here removes the runtime single point of failure for the flavour that cannot survive it.Verification — read this before merging
This PR is WIP.
GATE 3(build the SLE Micro installer and boot it in a multi-NIC VM) was NOT done.Blocked:
slem/5.5/Dockerfilestage 1 registers against SCC and requires aSUSE_REGCODEbuild secret (slem/5.5/build.sh:15-35). No registration code is reachable from this environment — Keeper reports persistent login is not usable non-interactively. Without it the image cannot be built, so no ISO and no VM boot.Verified
systemd-networkd, three NICs, real DHCP leases. All 17 checks intest/test-slem-network-defaults.shpass, including the before/after (unmanaged→configured),wait-onlinereturning 0, and both precedence cases. Run on a native arm64 Kairos base image with this overlay applied — not on the SLE Micro image (see below).COPY overlay/ /+ the assertionFROM us-docker.pkg.dev/palette-images/edge/kairos-slem:5.4-core-amd64-generic-v0.17.1: COPY lands both files at/usr/lib/systemd/network/with the expected content,/etc/systemd/network/stays empty, andsystemctl is-enabled systemd-networkd systemd-resolved sshdreturnsenabled×3. The same assertion correctly fails against the raw pre-kairos-initsle-micro/5.5base, so it is not vacuous.Not verified
ip -br link/networkctl list/systemctl status sshdon a booted SLE Micro host. The acceptance criteria are argued from the test above, not observed on the target OS.slem/5.5build has never been run — the SCC stage,kairos-init, and my two instructions in sequence. Only the last two were exercised, on a 5.4 base.systemd-networkdcannot start under emulation on this arm64 host (Could not create manager: Protocol not supported), so the test image was a native stand-in with the same overlay. systemd majors match (249), and the files are plain networkd config with no distro-specific syntax, but this is a stand-in. On an amd64 runner the same script pointed at the real image would be faithful — that is the remaining gate.docker build --checklint did not run (transientdocker.ioegress failure resolving the# syntax=image, unrelated to this change)./usr/libshould behave the same but I did not verify it.To take this out of WIP
On a host with a
SUSE_REGCODEand an amd64 Docker daemon:🤖 Generated with Claude Code