Daan De Meyer [Thu, 15 Feb 2024 09:01:07 +0000 (10:01 +0100)]
Manifest improvements
- Pass in Context instead of Config
- Fix the sandbox for all the executed commands
- Move complete_step() into record_packages()
- Fix writing of changelog
Daan De Meyer [Fri, 16 Feb 2024 08:43:02 +0000 (09:43 +0100)]
Introduce is_x86_variant() and is_arm_variant()
Let's make sure we always check for both the 64-bit and the 32-bit
variant where it makes sense to do so. Also make sure the Debian
default image can be built for x86.
Daan De Meyer [Thu, 15 Feb 2024 18:52:59 +0000 (19:52 +0100)]
Configure rpm dbpath using rpm macro
Let's get rid of all our cruft for fixing up the rpmdb location
after running rpm by simply making sure it gets written to the right
location in the first place.
Daan De Meyer [Thu, 15 Feb 2024 09:43:48 +0000 (10:43 +0100)]
Make package manager invoke() methods return the result
We also move the rpm database fixup call to the install() method
of the distribution so we don't try to do it every time we invoke
the package manager as it only needs to be done once.
Daan De Meyer [Wed, 14 Feb 2024 15:51:26 +0000 (16:51 +0100)]
Use a private file for the newuidmap/newgidmap locking dance
Using a publicly accessible file such as /etc/subuid means that other
applications can interrupt mkosi's operation by taking the lock
themselves, so let's lock a private temporary file instead which only
mkosi's user can lock.
Daan De Meyer [Wed, 14 Feb 2024 08:53:45 +0000 (09:53 +0100)]
Add used package manager to cache manifest
If the package manager changes, the cache is invalid as the
repository metadata directories change as well, so let's invalidate
the cache when that happens.
Daan De Meyer [Tue, 13 Feb 2024 20:24:42 +0000 (21:24 +0100)]
docs: Make "Building rpms from source" non-dnf specific
Let's make the doc non-dnf specific by not relying on dnf builddep
and using mkosi-install to install packages. This allows using the
same logic for opensuse images.
We also simplify things by only installing --buildrequires since
trying to cache --requires from the rpm spec isn't very useful as
most of the --requires dependencies are automatically generated and
won't be listed by rpmspec --requires in the first place.
Daan De Meyer [Tue, 13 Feb 2024 15:06:31 +0000 (16:06 +0100)]
Add Ubuntu Focal support to default image
We install fewer packages that are not available on Focal and make
sure to configure repart to disable an ext4 default feature that
isn't supported by the Jammy and Focal kernels.
Daan De Meyer [Tue, 13 Feb 2024 11:26:46 +0000 (12:26 +0100)]
Fail early with a clear error if keyring does not exist
We also introduce listify() and apply it to all repositories()
functions to make them return lists instead of generators to avoid
tripping up on the fact that generators can only be iterated once.
Daan De Meyer [Sun, 11 Feb 2024 09:59:57 +0000 (10:59 +0100)]
tree-wide: Introduce SandboxProtocol
Instead of passing a full sandbox command into the functions from
tree.py, archive.py, kmod.py and partition.py, let's instead pass
in a function that creates a sandbox, so we can pass in the required
options from the functions themselves. This reduces duplication a lot
as we don't have to specify all the sandbox options at each callsite.
Tj [Sat, 10 Feb 2024 16:40:18 +0000 (16:40 +0000)]
Do not use underscore in image names
When suffixing image_version (mkosi.version) do not use an underscore
since that breaks systemd-machined/machinectl because undescore are
invalid in machine names.
Daan De Meyer [Fri, 9 Feb 2024 11:12:22 +0000 (12:12 +0100)]
Only bind mount /var/lib/pacman/local from image if it exists
When running the finalize scripts, this directory might have been
cleaned up already as part of removing package manager metadata so
let's make sure we don't mount it in that case.
Daan De Meyer [Thu, 1 Feb 2024 11:32:43 +0000 (12:32 +0100)]
Decouple base trees from repository metadata snapshot
The syncing can be disabled with CacheOnly=metadata and we already
don't use repository metadata that's already populated so let's not
imply anything specific when using base trees so that base trees
without repository metadata can still be used to build extension
images.
Daan De Meyer [Wed, 31 Jan 2024 13:13:37 +0000 (14:13 +0100)]
Implement CacheOnly=metadata
We make CacheOnly= take an enum but keep backwards compat with the
boolean argument as well.
CacheOnly=metadata means we'll download packages but we won't sync
repository metadata. We also enable this in the kernel-install so that
our built initrds use exactly the same package versions as the host
system.
While we're at it we rename the internal variable to cacheonly instead
of cache_only (to match dnf's --cacheonly option). We keep the user
facing stuff the same to not break backwards compat.
We also make all of our enum functions take StrEnum as argument instead
of the generic enum.Enum.
Daan De Meyer [Tue, 30 Jan 2024 13:50:42 +0000 (14:50 +0100)]
Rework package manager caching
Currently, CacheDirectory= is used for all caching, both incremental
images and package manager cache. While this works great for incremental
images, there's a few issues with using CacheDirectory= for all package
manager caching:
- By default we don't do any caching, this has to be explicitly
configured by setting CacheDirectory=mkosi.cache or telling users
to manually create mkosi.cache. This means new users might be frustrated
by their image builds downloading everything again on subsequent builds.
- By doing package manager caches per individual mkosi project, we
unnecessarily download multiple copies of the same repo metadata and
packages.
- When using incremental images, if the post-install or finalize scripts
install extra packages, these packages can trigger repository metadata
updates, which will result in the image being built from two repository
metadata snapshots, one from when the incremental image was built, the
other from the new packages installed using the refreshed repository
metadata. Even if the scripts don't trigger repository metadata updates
themselves, because the cache is shared, the repository metadata could
already have been updated during another image build.
- When using base trees, any images using the base tree might trigger a
repository metadata update as well, resulting in the same issue, where
the image is built from multiple different snapshots of the repository
metadata.
To fix the first two issues, we introduce a new setting PackageCacheDirectory=
and make its default either a system or per user cache directory depending
on how mkosi is invoked. This makes sure we cache by default and use a shared
package manager cache directory so that we do not unnecessarily download duplicate
copies of repository metadata and packages
To fix the two remaining issues, we need to make sure we only sync repository
metadata once for each image. We opt to do this at the start of each image build
and configure the package manager commands to not do any metadata syncing by
default. To make sure the repository metadata snapshot stays available for
extension images and for incremental images, we copy the repository metadata from
the shared cache into the image itself at /mkosi/cache/<subdir>. This makes sure
that even if the repository metadata in the shared cache is refreshed by another
image build it won't remove the old snapshot for incremental builds or images
intended to be used as base trees.
To make sure the actual packages downloaded during the image build are still
written into the shared package cache, in finalize_package_manager_mounts(), we
bind mounts the relevant directories from the shared package cache instead of
from /mkosi/cache/<subdir> in the image to make sure that other image builds can
take advantage of the downloaded packages.
The /mkosi/ directory is removed from the image at the end of each image build
before packaging up the result unless we're building a directory or tar image
and CleanPackageMetadata= is explicitly disabled.
The initial sync we do at the start of each image build operates on the shared
package cache directory so that repository metadata is only refreshed once and
can be reused by other image builds.
Because package managers now prevent automatic syncing by default, we have to
rework the local package repositories slightly to make sure the local package
repository is still synced whenever it is updated. We get rid of the localrepo()
functions and opt to again write the repo definitions for the local package
repository inline to keep things simple and localized.
To avoid pacman from writing packages from the local package repository to the
shared package cache directory, we configure the local repository itself as an
additional read-only cache directory, which makes sure that pacman will read cached
packages from this directory but won't write any new packages to this directory.
For zypper we disable "keeppackages" for the local package repository to prevent
those packages from getting cached.
For dnf, we don't mount in any directory from the shared package cache for the
mkosi-packages repository to make sure it stays local to the image.
Apt doesn't support any mechanism that allows us to prevent packages from the
local repository from getting cached so we allow these to be written to the
shared package cache.
We also take the opportunity to rename the mkosi-packages repo to the mkosi repo,
and rename the accompanying config files as well;
Because pacman does not employ any sort of cache key for its repository metadata,
when using the default shared package cache directory, we use a subdirectory based
on the distribution, release and architecture that we're building for to prevent
any possible conflicts in the cache directory when different pacman based distributions
use the same repo identifiers.
To avoid issues when two instances of mkosi operate on the same package cache directory,
we take an advisory BSD lock on the cache subdirectory that we're going to sync or copy.
When building the default initrd, we make sure it uses the same repository snapshot
as the associated image.
Daan De Meyer [Tue, 30 Jan 2024 14:29:18 +0000 (15:29 +0100)]
Introduce PackageManager interface
Let's start introducing a common interface for package manager
implementations. This will allow us to slowly get rid of the
functions where we do logic for each package manager because we
don't know the one that's being used. For example we add scripts
for each package manager right now which we can get rid of with a
package manager interface.
This also allows for more intuitive naming of package manager functions,
instead of invoke_dnf() we can now write Dnf.invoke().