anaconda: Add experimental anaconda-based installation#202
anaconda: Add experimental anaconda-based installation#202
Conversation
The --cache=never flag (added in 50e7601 to avoid FD exhaustion) has a side effect: the guest kernel returns ENODEV for mmap() syscalls on virtiofs files. This breaks a surprising number of userspace tools: - ldconfig uses mmap to scan ELF headers, so it can't populate /etc/ld.so.cache - ctypes.util.find_library() parses ldconfig output, so it returns None for all libraries - pyudev uses find_library() to load libudev, so it fails with "ImportError: No library named udev" - anaconda uses pyudev for device discovery, so it fails to start The --allow-mmap flag tells virtiofsd to negotiate FUSE_DIRECT_IO_ALLOW_MMAP with the kernel (added in Linux 6.2 / FUSE 7.38), which permits mmap even when DIRECT_IO is enabled. This gives us the best of both worlds: - No FD exhaustion (still using --cache=never) - mmap works (ldconfig, pyudev, anaconda all function) Assisted-by: OpenCode (claude-sonnet-4-20250514)
Implement bootc container installation using anaconda as the installation engine with kickstart processing. Uses the ephemeral VM infrastructure to run anaconda in an isolated environment with proper access to block devices and container storage. Key implementation details: - User must provide kickstart file with partitioning and locale settings - bcvk injects ostreecontainer directive with --transport=containers-storage - Inject %pre script to configure container storage with host overlay - Inject %post script running 'bootc switch --mutate-in-place' to repoint the installed system to the registry image (for bootc upgrade to work) - Handle SSH exit code 255 as success when VM powers off after installation - Share disk creation logic via qemu_img::create_disk() Options: - --kickstart (-k): Required kickstart file path - --target-imgref: Registry image for bootc origin (defaults to image arg) - --no-repoint: Skip %post repointing if user handles it themselves The anaconda installer container (localhost/anaconda-bootc) is based on fedora-bootc with anaconda-tui installed. Build instructions in containers/anaconda-bootc/. Assisted-by: OpenCode (Claude sonnet-4-20250514)
There was a problem hiding this comment.
Code Review
This pull request introduces an experimental anaconda-based installation method for bootc images, including a new Dockerfile, documentation, and integration tests. While the code is well-structured, there are significant security concerns regarding how user-supplied image names and references are handled when generating Kickstart files. Specifically, the code is vulnerable to both Command Injection in the %post script and Kickstart Directive Injection via the image argument. These should be addressed by properly quoting and validating all user-supplied strings. Additionally, a minor issue was noted regarding a hardcoded value in the generated kickstart script, which could be made dynamic for better flexibility.
| set -euo pipefail | ||
| # Set up container storage with host overlay access | ||
| mkdir -p /var/lib/containers | ||
| mount -t tmpfs -o size=10485760k tmpfs /var/lib/containers |
There was a problem hiding this comment.
The size of the tmpfs for /var/lib/containers is hardcoded to 10GB. This might not be sufficient for all installation scenarios and is inconsistent with the dynamic sizing used for the /var/tmp tmpfs in generate_install_script. Consider making this size dynamic, for example, by basing it on the disk or image size.
| return utils::parse_size(size_str); | ||
| } | ||
| let image_size = images::get_image_size(&self.image)?; | ||
| let min_4gb = 4u64 * 1024 * 1024 * 1024; |
There was a problem hiding this comment.
This needs a rationale and should be const
|
|
||
| /// Disk size to create (e.g. 10G, 5120M) | ||
| #[clap(long)] | ||
| pub disk_size: Option<String>, |
There was a problem hiding this comment.
Should use shared size parser
| let mut ostreecontainer_added = false; | ||
| let mut pre_added = false; | ||
|
|
||
| for line in user_kickstart.lines() { |
There was a problem hiding this comment.
Should factor out a mod kickstart
| // Before first section, add ostreecontainer and our %pre | ||
| if !ostreecontainer_added { | ||
| result.push_str(&format!( | ||
| "ostreecontainer --transport=containers-storage --url={}\n", |
There was a problem hiding this comment.
Detect if target anaconda has the bootc verb?
| additionalimagestores = ["/run/virtiofs-mnt-hoststorage"] | ||
| EOF | ||
|
|
||
| cat > /etc/containers/policy.json << 'EOF' |
There was a problem hiding this comment.
This shouldn't be necessary by default
| Ok(result) | ||
| } | ||
|
|
||
| /// Generate the %pre section that sets up container storage |
There was a problem hiding this comment.
I think we can maybe move this to the Anaconda container image as a systemd unit.
| let mut file = std::fs::File::create(&path).context("Failed to create kickstart file")?; | ||
| file.write_all(content.as_bytes())?; | ||
| file.sync_all()?; |
| [ -e "$TARGET_DISK" ] || {{ echo "ERROR: Target disk not found"; exit 1; }} | ||
|
|
||
| export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 | ||
| anaconda --text --noninteractive --kickstart "$KS_PATH" || ANACONDA_EXIT=$? |
There was a problem hiding this comment.
It's interesting, does anaconda itself not run via a systemd unit by default? Needs investigation.
| rm -rf /var/lib/containers | ||
| ln -sr /var/tmp/containers /var/lib/containers | ||
|
|
||
| AIS=/run/virtiofs-mnt-hoststorage |
There was a problem hiding this comment.
Should not duplicate the %pre content
Implement bootc container installation using anaconda as the installation
engine with kickstart processing. Uses the ephemeral VM infrastructure to
run anaconda in an isolated environment with proper access to block devices
and container storage.
Key implementation details:
the installed system to the registry image (for bootc upgrade to work)
Options:
The anaconda installer container (localhost/anaconda-bootc) is based on
fedora-bootc with anaconda-tui installed. Build instructions in
containers/anaconda-bootc/.