Create /etc files, symlinks and folders if they don't exist

The existing tmpfile logic took care of folders that the ebuild keepdir
directive wanted to exist on the OS. However, files and symlinks were
not created, causing them to be missing if we didn't explicitly modify
the ebuild files in coreos-overlay to find a solution with tmpfiles or
patching the paths to /usr.
Add logic to create missing files and symlinks through tmpfile
directives and preserve any directory, not only the ones with the
keepdir ebuild directive. Also remove any state from the rootfs to make
sure that we don't rely on it when testing our images before the
release. To create the files the final /etc folder is moved to
/usr/share/flatcar/etc and in the future this can be used for a better
logic that could take care of updating files the user didn't modify,
deleting those that aren't needed anymore, and even reconciling changed
files through a 3-way merge, instead of using simple tmpfile logic.
This commit is contained in:
Kai Lueke 2022-03-25 14:05:00 +01:00
parent 7de89044c7
commit e263b4bde5
3 changed files with 37 additions and 6 deletions

View File

@ -658,6 +658,7 @@ finish_image() {
${tmp_ignore} "${root_fs_dir}/var"
sudo "${BUILD_LIBRARY_DIR}/gen_tmpfiles.py" --root="${root_fs_dir}" \
--output="${root_fs_dir}/usr/lib/tmpfiles.d/base_image_etc.conf" \
--files="/usr/share/flatcar" \
${tmp_ignore} "${root_fs_dir}/etc"
# Only configure bootloaders if there is a boot partition
@ -692,6 +693,17 @@ EOF
fi
write_contents "${root_fs_dir}" "${BUILD_DIR}/${image_contents}"
# Backup the /etc contents to /usr/share/flatcar/etc to serve as source
# for creating missing files
sudo cp -a "${root_fs_dir}/etc" "${root_fs_dir}/usr/share/flatcar/etc"
# Remove the rootfs state as it should be recreated through the
# tmpfiles and may not be present on updating machines. This
# makes sure our tests cover the case of missing files in the
# rootfs and don't rely on the new image. Not done for the developer
# container.
if [[ -n "${image_kernel}" ]]; then
sudo rm --one-file-system -rf "${root_fs_dir}/etc" "${root_fs_dir}/var"
fi
# Zero all fs free space to make it more compressible so auto-update
# payloads become smaller, not fatal since it won't work on linux < 3.2

View File

@ -19,6 +19,7 @@ def main():
parser = optparse.OptionParser(description=__doc__)
parser.add_option('--root', help='Remove root prefix from output')
parser.add_option('--output', help='Write output to the given file')
parser.add_option('--files', default='', help='Also works on files and symlinks and uses the given path as source for copying files')
parser.add_option('--ignore', action='append', default=[],
help='Ignore one or more paths (use multiple times)')
opts, args = parser.parse_args()
@ -32,8 +33,11 @@ def main():
assert path.startswith(opts.root)
for dirpath, dirnames, filenames in os.walk(path):
if any(f.startswith('.keep') for f in filenames):
keep.add(dirpath)
keep.add(dirpath)
if opts.files:
for f in filenames:
if not f.startswith('.keep'):
keep.add(os.path.join(dirpath, f))
# Add all parent directories too
for path in frozenset(keep):
@ -61,8 +65,22 @@ def main():
if stripped in opts.ignore:
continue
info = os.stat(path)
assert stat.S_ISDIR(info.st_mode)
target = '-'
info = os.stat(path, follow_symlinks=False)
if not opts.files:
assert stat.S_ISDIR(info.st_mode)
if stat.S_ISDIR(info.st_mode):
entry = 'd'
elif stat.S_ISLNK(info.st_mode):
entry = 'L'
target = os.readlink(path)
elif stat.S_ISREG(info.st_mode):
entry = 'C'
assert opts.files
target = os.path.join(opts.files, stripped.lstrip('/'))
assert target.startswith(opts.files)
else:
continue
mode = stat.S_IMODE(info.st_mode)
try:
@ -74,8 +92,8 @@ def main():
except KeyError:
group = str(info.st_gid)
config.append('d %-22s %04o %-10s %-10s - -'
% (stripped, mode, owner, group))
config.append('%s %-22s %04o %-10s %-10s - %s'
% (entry, stripped, mode, owner, group, target))
if opts.output:
fd = open(opts.output, 'w')

View File

@ -0,0 +1 @@
- Added tmpfile rules to create missing folders, files, and symlinks under `/etc` and ship with an empty rootfs to ensure that we don't rely on files the updating machines may be missing and that all needed files have a tmpfile rule. To disable the creation of a file, symlink, or folder with the default contents, create an empty file or a symlink to `/dev/null` instead of removing it. ([PR#264](https://github.com/flatcar-linux/scripts/pull/264))