Conversation
os.WriteFile follows symlinks, and most systemd distributions ship /etc/resolv.conf as a link into systemd-resolved's runtime directory. The nameservers therefore landed in a file resolved owns and regenerates, on a tmpfs, so the dns stage never stuck. In an initramfs that directory does not exist yet and the whole stage failed with ENOENT. Write a sibling and rename over the path instead. Rename acts on the link rather than its target, so the caller gets a regular file where it asked for one, resolved's file is left alone, and no reader can observe a half-written resolv.conf. The same function ignored the vfs.FS it was handed and went straight to the os package, which wrote the host's /etc/resolv.conf no matter which filesystem the executor was pointed at. Route it through fs, like every other plugin, and create the parent directory when it is missing. Signed-off-by: Ettore Di Giacinto <mudler@kairos.io>
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.
Fixes the second half of kairos-io/kairos#835, the one left open when the initramfs
systemd-resolveddracut module was handled: thedns:stage does not stick on a systemd host.The bug
Buildusedos.WriteFile, which follows symlinks. Kairos points/etc/resolv.confat systemd-resolved's runtime file on every systemd image (kairos-init/pkg/bundled/cloudconfigs/05_network.yaml:71doesrm /etc/resolv.conf && ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf), and most systemd distributions do the same on their own. So the nameservers went into a file resolved owns and regenerates, on a tmpfs. In an initramfs that directory does not exist yet, and the stage failed outright.A/B with the same yaml, against a tree whose
/etc/resolv.confis that symlink:/etc/resolv.conf0644, the nameservers/run/systemd/resolveyet)level=fatal ... open /etc/resolv.conf: no such file or directorySeparately, the plugin took a
vfs.FSand never used it. Handed a filesystem rooted elsewhere it still wrote the host's/etc/resolv.conf; the only reason the existing test passed was that it read the result back withos.Open. Every other file-writing plugin here goes throughfs.The fix
Write a sibling and
Renameover the path. Rename acts on the link rather than its target, so the caller gets a regular file where it asked for one, resolved's file is left alone, and no resolver can read a half-writtenresolv.conf. Route the whole function throughfs, and create the parent directory when it is missing.Buildgains anfs vfs.FSparameter. It has no callers outside this package.Tests
Six specs in
dns_test.go, covering the symlink, the dangling symlink, the vfs, the missing parent directory, and search/options. Mutation-checked one layer at a time: revertingfs.*toos.*reds all six, writing the path directly instead of renaming reds exactly the two symlink specs, dropping theMkdirAllreds exactly the parent-directory spec. Suite is back to its pre-existing baseline on this box (90 passed / 30 failed, the 30 being thelayoutanduserspecs that needmkfsand root).Not in scope
Making the stage speak to
systemd-resolvednatively (resolvectlor a.networkdrop-in) instead of writingresolv.confat all is a separate design call, and I have left it alone. This change only makes the plugin honour the path it was given.