Look up qemu and virt-fw-vars in extra search paths
Because qemu uses OVMF firmware descriptions from /usr, we look
those up in the same root that we'll be invoking qemu from. Because
virt-fw-vars operates on the same files, we also invoke it in the
same root that we find qemu in.
There could potentially be a huge amount of modules and firmware
which makes these log messages very noisy. Let's drop them to make
debug logs less annoying to parse.
Assign return code before calling sys.excepthook()
It seems sys.excepthook() can raise its own exception? I'm not entirely
sure what's going on, but as a safety measure, let's assign the correct
return code before we invoke sys.excepthook() so that we always exit with
the right returncode.
There's various crypto directories all across the kernel modules
tree. Let's make sure we include all of them so that everything
required to do crypto is always available from the initrd.
Don't copy /var/lib/pacman/local when copying repository metadata
/var/lib/pacman/local contains the local database of installed packages.
When using "--package-cache-dir /var", we'd end up copying the local
database of the host which means pacman thinks packages are already
installed in the image even though they aren't.
If the image is nocow, make the ephemeral copy nocow as well
On btrfs, VM images are generally recommended to be made nocow as
cow (copy-on-write) and random writes don't play well together. Let's
take this into account in copy_ephemeral() and make the ephemeral
copy nocow as well if the source is nocow.
This does not work as we call have_cache() to determine whether
we need to clean the tools tree or not and when running as root to
boot after building an image the UID/GID will differ and the tools
tree will incorrectly be considered out of date.
Let's move the UID/GID check out of have_cache() and into reuse_cache()
instead. reuse_cache() always runs after we've already potentially
unshared the user namespace and become root, so checking the owner of
the cache directory against the current UID should be a valid check
there.
bubblewrap uses pivot_root() which doesn't work in the initramfs as
pivot_root() requires / to be a mountpoint which is not the case in
the initramfs. So, to make sure mkosi works from within the initramfs,
let's make / a mountpoint by recursively bind-mounting / (the directory)
to another location and then switching root into the bind mount directory.
We can't check the current uid in sandbox_cmd() as it might still
change, for example in start_virtiofsd() where before we run bwrap
we might run become_root_cmd() to become root.
Make make_cpio() take a list of files relative to the root directory
We operate on absolute paths all the time in kmod.py only for them to
be made relative to the root directory just before they are passed to
cpio. Let's save on the amount of allocations by always operating on
paths relative to the root directory.
Because rglob() doesn't support returning paths relative to the given
directory, we chdir() into the root directory before globbing instead.
Sadly, shellcheck does not support zsh [1], and it's not even possible
to evaluate the script with zsh because it fails with:
_arguments:comparguments:327: can only be called from completion function
So the zsh script shall not be checked.
readarray is used to create arrays. The one clear advantage is that we don't need to
override $IFS. Together with the change to not assign an unused variable, this
removes shellcheck warnings.
Nevertheless, shellcheck would still warn about the file because it doesn't
know about the variables that are in the part that is generated dynamically.
Also, move more content to the static resource file. The order of declarations
doesn't matter, so it's fine if the variables are defined below the functions.
Also, adjust the formatting in the bash resource to follow the usual style
with 'if something; then' on one line.
Jörg Behrmann [Sun, 16 Jun 2024 13:11:14 +0000 (15:11 +0200)]
completion: add zsh
This completion of verbs is based on _timedatectl in systemd repo.
Completion for short options doesn't work. It also doesn't work for
timedatectl, so this needs to be fixed in both places.
Co-authored-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Stop mounting build sources when running package managers
We now have PackageDirectories= to make local packages available
for installation so let's stop mounting build sources when running
package managers and tell users to use PackageDirectories= instead.
Recommend PackageDirectories= to install local packages
apt-get requires absolute paths to be specified and doesn't work
with relative paths. Let's instead recommend PackageDirectories=
which we know works the same for all distributions.
Force user namespace in bubblewrap if we're not running as root
Depending on whether bwrap is installed setuid or not it might try
to not create a user namespace. Let's explicitly tell it to create
one if we're not invoking it as root to make sure one is always
created.
Choose default tools tree distribution based on host distribution
Let's choose the default tools tree distribution based on the host
distribution instead of the target distribution. Why? When building
a Fedora image from Ubuntu, It's much more likely that apt-get will
be installed to build a Debian tools tree rather than requiring dnf
to be installed to build a Fedora tools tree.
Python does not have block scoped variables which messes up typing
if you use the same variable name in 2 unrelated blocks so let's
rename this one to make mypy happy.
Let's simplify the config parsing implementation by making ParseContext
a regular class instead of a singleton. Additionally, we make ConfigAction
a global class and slightly change the behavior of --include= on the command
line by parsing all given includes after parsing all the other command line
arguments.
Make sure we always update the local repository metadata
The latest release of dnf5 introduced a change in behavior causing us
to not always sync the local repository metadata. To mitigate this, let's
always specify --refresh or similar for all package managers when we sync
the local repository to make sure its metadata is updated.
Let's leave this up to the individual subimage build scripts instead,
so that it's also possible for different subimages to share a build
directory if they want to do so.
Let's make BuildSources=, BuildSourcesEphemeral=, WithTests= and
WithNetwork= universal so that packages can easily be built in a
subimage instead of in the main image build.
We can't mark Environment= as a universal setting as only some environment
variables should be universal and others shouldn't be. So let's introduce
PassEnvironment= to mark specific environment variables as universal so that
they are passed to subimage builds.
Let's allow scripts to access the build directory so that outputs produced
by previous (sub)image builds can be accessed. Let's mount the build directory
read-only so that these scripts can't actually write to it.
Downgrade SELinuxRelabel=yes to SELinuxRelabel=auto for the initrd
Otherwise we fail if there's no policy installed in the initramfs.
Putting a policy in the initramfs isn't really a thing so let's not
fail if there is one available but still relabel if there is one
installed.
Let's track the modification timestamps of the packages from configured
package directories so we can rebuild the image if new packages appear
or are removed or changed.
For packages that should not be available when building the cached
image but should be available when installing volatile packages.
Additionally, we have build scripts write their packages to a separate
directory instead of the repository directory and later on pass these
packages as a separate volatile package directory to the default initrd
build.
This will allow us to introduce proper caching for package directories
in the next commit.
Only install systemd-ukify on Fedora on UEFI architectures
- systemd-ukify is only available on Fedora on UEFI architectures,
so let's not try to install it on other architectures.
- systemd-ukify is not in CentOS Stream 10 at the moment, so let's
not try to install it on CentOS just yet.
In preparation for the next commit, let's decouple the location of
the local repository from the location of the package directory where
scripts can look for packages.
Now that we have a Repositories= match, we can conditionally enable
EPEL for CentOS Stream 9 only and override the repositories when we
call mkosi dependencies. This means that the CentOS Stream 9 default
tools tree will have all the EPEL packages but we won't list them in
the output of mkosi dependencies.
We also add various missing packages to the CentOS Stream default tools
tree.