Skip to content

vm-less and daemon-less ELBE build without mknod - #487

Open
koalo wants to merge 19 commits into
Linutronix:masterfrom
koalo:devel/koalo/container-nomknod
Open

vm-less and daemon-less ELBE build without mknod#487
koalo wants to merge 19 commits into
Linutronix:masterfrom
koalo:devel/koalo/container-nomknod

Conversation

@koalo

@koalo koalo commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

This supersedes #482 by removing the manual mknod procedures with passing udev and /dev directly into the container for the rootful case.

Also reordered the commits as discussed:

  1. ELBE without initvm (rootful)

fc80da4
54c6257
da13574

  1. Container for ELBE without initvm (rootful)

d532e23
9843820
d7f66a3
707b6c6

  1. Test for 2)

ea2994e
ec47114
b5b9d22

  1. ELBE without initvm (rootless)

No additional commits, but requires to manually unshare if not done via container.

  1. Test XML that allows to build rootless

0095a8d

  1. Container for ELBE without initvm (rootless)

43a09d5
41e12bf
76aa59e
79d2fd0

  1. Test for 6)

d4cabf0

@t-8ch t-8ch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I focused on step 1) for now.
You could also drop the other steps for now and we do one after the other.

Comment thread elbepack/commands/build.py Outdated
elif not xmlfile.endswith('.xml'):
args.parser.error('Unknown file ending (use either xml or iso)')

local_build_with_repodir_and_dl_result(xmlfile, cdrom, args.base_image, args)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicated with the initvm submit path. It should be in a helper.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread elbepack/commands/build.py Outdated
cdrom = xmlfile
xmlfile = tmp.fname('source.xml')
elif not xmlfile.endswith('.xml'):
args.parser.error('Unknown file ending (use either xml or iso)')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can handle this in the input arguments type.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread elbepack/localbuildaction.py Outdated


def local_build_with_repodir_and_dl_result(xmlfile, cdrom, base_image, args):
os.makedirs(args.build_dir, exist_ok=True)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pathlib please

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread elbepack/localbuildaction.py Outdated
# check, whether everything is ok.
prj = pm.db.get_project_data(prjdir)
if prj.status != 'build_done':
raise CliError(191, f'Project build was not successful, current status: {prj.status}')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea behind these explicit error numbers is that they are unique.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to 213 which should be the smallest number that is still free (hopefully...).

https://github.com/Linutronix/elbe/pull/487/changes#diff-069babafd9ca08b3f8b23e08b0b493d5a2f570fade3f6e1a59e1e63da3a827e4R63

@@ -0,0 +1,159 @@
# ELBE - Debian Based Embedded Rootfilesystem Builder

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains a lot of duplicated code, can we reduce this?
For example with a shared interface.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread elbepack/asyncworker.py Outdated
class BuildJob(AsyncWorkerJob):
def __init__(self, project, build_bin, build_src, skip_pbuilder, base_image_path):
def __init__(self, project, build_bin, build_src, skip_pbuilder,
base_image_path, exclude_initvm_pkgs=False):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the argument to a function is always passed, please remove the default argument.
(Some other functions may duplicate all default arguments anyways, keep it there for consistency)

Comment thread elbepack/localbuildaction.py Outdated

pm.build_project(prjdir, args.build_bin, args.build_sources, bool(cdrom),
uploaded_base_image_path)
uploaded_base_image_path, args.exclude_initvm_pkgs)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will always be True, no?
Maybe we can then also get rid of the ugly args.exclude_initvm_pkgs assignment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread elbepack/repomanager.py
elif init_attr is not None:
self.attrs = [init_attr]
else:
self.attrs = []

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you split the changes to the repomanager into its own commit, explaining what is going on?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now in a separate commit

f1ca16b

Comment thread elbepack/repomanager.py
self.gen_repo_conf()

def _reprepro(self, args):
do(['reprepro', *args], env_add={'GNUPGHOME': self.gnupg_home})

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split the creation of the helper into its own commit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now in a separate commit
b0ff3c5

Comment thread elbepack/paths.py
BINARIES_MAIN_DIR = f'{ELBE_CACHE_DIR}/binaries/main'
BINARIES_ADDED_DIR = f'{ELBE_CACHE_DIR}/binaries/added'
INITVM_BIN_REPO_DIR = f'{ELBE_CACHE_DIR}/initvm-bin-repo'
INITVM_GNUPG_HOME = f'{ELBE_CACHE_DIR}/gnupg'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this commit earlier into the series.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now directly after the extract initvm packages commits.

@koalo
koalo force-pushed the devel/koalo/container-nomknod branch from d4cabf0 to 3b2caf8 Compare September 8, 2026 13:27
koalo added 19 commits September 8, 2026 16:34
Allow RepoBase/CdromInitRepo to be constructed without init
attributes (init_codename=None), and to pick up an existing repo
directory that does not yet have a conf/distributions file, treating
it like a fresh repository in that case.

This prepares the ground for skipping the initvm CDROM entirely on
initvm-less builds.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Adding initvm packages to the CDROMs is not reasonable when there is no
initvm. Therefore, exclude them. Also, provide this option as CLI
parameter (default off) for initvm builds for consistency.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Introduce a reprepro helper that wraps the reprepro invocations
which set GNUPGHOME, instead of repeating the env_add argument at
every call site.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
The gnupg home directory used for signing and verifying repositories
was hardcoded to /var/cache/elbe/gnupg throughout the signing helpers
and repository classes. Pass it explicitly instead, so callers can
point them at a project-specific keyring.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
More of the code from initvmaction.py can be moved to
buildsubmitaction.py by introducing an abstract base class.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Add a new top-level "elbe build" command as alternative
to "elbe initvm submit". It drives the project manager directly
in-process, without any daemon or SOAP communication. It is meant to
be used in an environment that already provides the required
isolation.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
The rbind-based pseudo filesystem mounting for chroot() needs the
_Mount helper, but imgutils.py cannot be imported from shellhelper.py
without creating a cyclic dependency. Move _Mount there first.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
…cratch

Several operations require a chroot with the pseudo filesystems (/proc,
/sys and /dev) in it. Inside a container, the container runtime already
protects parts of it (like /proc/kcore) by overlaying it with a null
bind mount. Doing a fresh mount from scratch (e.g. mount -t proc None foo)
inside a completely new mount and user namespace, would expose the
content again, so the kernel has explicit procection against it
(-> mount_too_revealing).

But we do not need fresh pseudo filesystems. We can just rebind what we
already have. The only issue with that is that we need to scope it more
tightly around the operations that actually require this setup with
chroot and pseudo filesystems, otherwise we would fill up the newly
created filesystem with stuff from the pseudo filesystems we do not
need.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Several actions require elevated privileges for losetup or mknod.
Instead of starting the build and then later failing with an error
message, check beforehand for critical elements in the XML and print
a respective error message.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
With the recent additions, it is no longer necessary to spawn an initvm
to build ELBE images. Therefore, provide a container that enables this
use case and replace the existing legacy containerfile with it.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
/tmp is usually RAM-backed, so when putting build artifacts there, it
will fill up very quickly and exhaust the RAM. Therefore, use /var/tmp
per default. On Debian systems /var/tmp will still follow a retention
policy, so any potential leftovers will be removed after 30 days
(in the default configuration).

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Split the test_xml to only contain code that is not directly related to
the initvm. This will enable us in the next step to add further tests
that will use the container-based approach.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Provide a test driver to run the same tests as for the initvm
in test_xml.py for the container-based build as well.

Run all tests as root, skip if we are not root.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Build a simple image without a bootloader to demonstrate
an ELBE build that does not require elevated privileges.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
If there is no udev running (like when we are inside a container),
we do not need to wait for it.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
…without udev

Setup UUID as needed e.g. for grub, because that is usually also done by udev.
So without udev, we need a replacement for that functionality.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
By unsharing into a new user and mount namespace, we get sufficient
permissions to perform (bind) mounts needed for the build process.

With this, we can avoid the need for an explicit --cap-add CAP_SYS_ADMIN

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Add how to build rootless for ELBE XMLs with a reduced
feature set.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Detect whether the XML under test actually needs a rootful
container by checking xml_needs_rootful(). When it does not,
run the container rootless via --userns auto instead of
requiring elevated privileges, and only skip the test when a
rootful container is required and the tests are not run as root.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
@koalo
koalo force-pushed the devel/koalo/container-nomknod branch from 3b2caf8 to 90dc4e3 Compare September 8, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants