Daan De Meyer [Thu, 4 May 2023 10:47:24 +0000 (12:47 +0200)]
Rework output related logic
- Let's store the output as a "base" name without any suffixes from
which we construct all other output paths.
- Let's not allow --output to be specified as a path anymore and
always put it in the configured output directory.
- Let's return all output paths as strings instead of paths. As
strings, we'll get typing errors if we try to use these as paths
without joining them with a directory first, which can be either the
output directory or the staging directory.
- Let's always create a symlink from the "base" name to the full
output path so it can be referred to regardless of the output
format, compression or image version that's used.
- Let's make sure we compress split partitions if requested
Daan De Meyer [Wed, 3 May 2023 12:15:22 +0000 (14:15 +0200)]
opensuse: Use dnf instead of zypper
Let's reduce the number of package managers we use by using dnf to
build opensuse images.
The only caveat is that extra GPG keys are listed in repomd.xml for
the opensuse repos, so we have to download that file and parse it to
figure out the extra keys that we have to write to the repo configs.
Ensure output is compatible with systemd-sysupdate
When using `systemd-sysupdate` it is wise to use split artifacts and to
compress artifacts. These changes ensure that split artifacts are compressed
and the file paths are stored in the checksum.
Please note that `systemd-sysupdate` expects a checksum name of `SHA256SUMS`
and uses the contained file names to determine which files to download. The
compression suffix is also used to determine how to decompress files.
Additional CI checks have been added to make sure no regressions in output
format occur.
Daan De Meyer [Wed, 3 May 2023 11:25:07 +0000 (13:25 +0200)]
Drop gpg path locations
All of our gpg paths point to locations in rpms gpg database so they
should already be known by dnf and as such there's no point in listing
them explicitly in the config file. Let's only keep the urls in mkosi.
When using RemovePackages= apt may refuse to remove what it considers
essential packages even when they are effectively empty meta packages or
contain only usr/share/doc/${package}/
This causes build failure like this:
Reading state information...
Package 'netcat-openbsd' is not installed, so not removed
Package 'net-tools' is not installed, so not removed
Package 'man-db' is not installed, so not removed
Package 'groff-base' is not installed, so not removed
The following packages will be REMOVED:
cron* dmidecode* fdisk* ifupdown* init* iproute2* iputils-ping*
isc-dhcp-client* isc-dhcp-common* kmod* libbpf0* libbsd0* libcap2-bin*
libdns-export1110* libedit2* libelf1* libfdisk1* libisc-export1105*
libjansson4* libmd0* libmnl0* libnftables1* libnftnl11* libxtables12*
nano*
netbase* nftables* udev* vim-common* vim-tiny* xxd*
WARNING: The following essential packages will be removed.
This should NOT be done unless you know exactly what you are doing!
init
0 upgraded, 0 newly installed, 31 to remove and 0 not upgraded.
E: Essential packages were removed and -y was used without
--allow-remove-essential.
‣ "apt-get purge vim-tiny vim-common nano nftables netcat-openbsd
netbase net-tools isc-dhcp-common isc-dhcp-client iputils-ping iprout
e2 udev kmod fdisk dmidecode man-db init ifupdown groff-base cron"
returned non-zero exit code 100.
Traceback (most recent call last):
File "/usr/lib/python3.9/runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
As we do know what we are doing to have configured these removals, tell
apt to allow it.
Presets can be defined in mkosi.presets/. A preset is just like a
regular config file/directory, except that mkosi can build multiple
presets sequentially.
If mkosi.presets/ exists, for each preset mkosi will read the global
configuration, followed by the individual preset configuration. It
will then build each of the presets in alpha-numerical order. Later
presets can use outputs of earlier presets, specifically using the
BaseTrees= and Initrds= options.
While this has many use cases, one promising use case is to allow
building an initrd and a final image that uses that initrd within a
single invocation of mkosi.
Let's stop running kernel-install in favor of always doing prebuilt
initrds by default. We reimplement the depmod hook of kernel-install
ourselves (required for centos stream 8).
If no initrd is provided by the user, we build a minimal one ourselves
that's sufficient to boot in a qemu VM. If the default initrd is not
sufficient, the upcoming preset support can be used to build a custom
initrd instead.
Switch back to using ttyS0 as the default serial console
virtio_console is not always a builtin kernel module on all the
distributions we support. This means that the kernel can only
start logging to it after the initramfs has been unpacked and the
virtio_console module has been loaded from it. Any message that's
logged to kmsg before that dissapears into the void which makes
debugging boot failures rather difficult.
Instead, until systemd-stub is recent enough in all supported distros
to receive extra kernel cmdline arguments via smbios, let's use a
default kernel cmdline of "console=ttyS0" so that the serial console
works by default but can still be overridden by users.
centos: Make sure glibc-all-langpacks doesn't get installed
On CentOS 8, glibc-all-langpacks is pulled in as a dependency of
filesystem. Let's make sure dnf prefers glibc-minimal-langpack by
installing it explicitly.
Currently, when base trees are used in incremental mode, we cache
the base trees as well. When running from a cache copy, any changes
to the base trees are not taken into account. Let's change this and
only cache the files we add/change/delete on top of the base layers.
This makes sure that we can still use our cache even if the base layer
changes, since we won't ignore all changes made to the base layer.
hash signing: Use keyring of running user for non-root builds
`gpg` will attempt to use the root user keyring When running as a non-root
user instead of using the keyring of the user that is executing `mkosi`.
This change will attempt to use the keyring given by `GNUPGHOME` and
fallback to using `~/.gnupg`.
While SUDO_UID and SUDO_GID are useful, since sudo allows to run things as
different UID and GID, SUDO_USER is less useful, since it can't change the
mapping from UID to name in the namespace it's in. Let's cut out the middleman
of getpass.getuser, that looks through several more environment
variables (LOGNAME, USER, LNAME, USERNAME) before falling back to os.getuid and
looking up the corresponding name and do that right away.
We don't really care which version is used exactly, but 24 is almost
certainly not the right one. By not specifying the version we let mkosi
pick something suitable.
This header is rendered in the github preview in a fairly ugly way.
Nevertheless, we can't get rid of the whole thing because then pandoc generates
a man page without a header. But let's at least drop the info about authors and
date to make the whole thing less prominent.
Let's move the cache images to mkosi.cache/ and go back to non
distro specific output directories. This gives us a stable path
for the build outputs that doesn't depend on the specific distro or
version used.
Georges Discry [Sun, 23 Apr 2023 10:27:01 +0000 (12:27 +0200)]
Enable --repo-dir for Debian and Ubuntu
Additional repositories can now be configured for Debian and Ubuntu.
Because APT can only be configured with a single path for
`Dir::Etc::sourceparts`, the content of the directories listed in
`repo_dirs` are copied in a `apt/sources.list.d` directory managed by
mkosi outside the image root. Therefore, only one file will be kept if
several files have the same name.
Like the main `sources.list` generated by mkosi, the additional
repositories are copied in the image if APT is installed.
- Remove optional exception argument of die() in favor of just using
logging.error() and re-raising the exception
- Instead of raising RuntimeError in die(), just call sys.exit()
instead which raises SystemExit.
- Show stacktrace of every exception that isn't SystemExit,
KeyboardInterrupt or subprocess.CalledProcessError.
Revert back to shell based chmod solution for bwrap
Mounting the host directories doesn't work because those directories
are owned by root on the host which translates to nobody in the user
namespace, breaking systemd tmpfiles tests.
Use conditional apivfs with Debian/Ubuntu and Arch as well
Arch's filesystem package ships apivfs directories as well and
in Debian/Ubuntu, we don't want to have apivfs mounted when running
the apt update and when only downloading packages.
Let's drop the support for multiple string arguments since we only
have "run" anyway and make --boolean a simple yes/no option. To
get an interactive shell on failure, a new option --debug-shell is
added.
- To split up our dependencies more, we need to make run.py
independent of MkosiState, so let's do that.
- To get rid of the shell hacks in both functions to chmod /tmp,
/var/tmp and /dev/shm, let's just mount the relevant files from
the host which have the right permissions.
- Fixing the above exposed a bug in the logic to set up rpm based
systems, which all ship a filesystem package that includes
directories such as /tmp, /proc, /sys, ... which we overmount
with apivfs or tmpfs filesystems when running rpm, causing errors
when the filesystem package tries to set up these directories. To
ensure these directories are created with the permissions from the
filesystem package, the run_with_apivfs() function is renamed to
bwrap() and gains an apivfs argument, which takes a path to set
up apivfs directories in. If not provided, no apivfs is set up.
This is then used to install the filesystem package without apivfs
so that the directories can be created with the right permissions.
- The various rpm distributions now install the filesystem package
instead of the setup package by default, so we can disable apivfs
properly while filesystem is being installed. system-user-root
was removed for opensuse because the filesystem package depends on
it.
On CentOS, we were creating the wrong symlink. Let's use a proper
relative symlink that always works regardless of whether we're chrooted
or not.
On Debian/Ubuntu, we weren't creating a symlink at all. So let's make
sure we also create a symlink there and use a relative symlink there as
well.
We use os.path.relpath() because Path().relative_to() can only do relative
paths to subpaths which isn't the case here. In the future we can set
strict=False and use relative_to().