Document OSBuild architecture and enhance debootstrap stage
Some checks are pending
Checks / Spelling (push) Waiting to run
Checks / Python Linters (push) Waiting to run
Checks / Shell Linters (push) Waiting to run
Checks / 📦 Packit config lint (push) Waiting to run
Checks / 🔍 Check for valid snapshot urls (push) Waiting to run
Checks / 🔍 Check JSON files for formatting consistency (push) Waiting to run
Generate / Documentation (push) Waiting to run
Generate / Test Data (push) Waiting to run
Tests / Unittest (push) Waiting to run
Tests / Assembler test (legacy) (push) Waiting to run
Tests / Smoke run: unittest as normal user on default runner (push) Waiting to run

- Create comprehensive OSBuild architecture documentation
- Document buildroot isolation and object store patterns
- Enhance debootstrap stage to follow OSBuild patterns exactly
- Add proper metadata generation and filesystem mounting
- Maintain 1:1 compatibility with OSBuild design
- Mark foundational architecture tasks as complete
This commit is contained in:
robojerk 2025-08-22 20:49:53 -07:00
parent 01562657fb
commit b689f3e868

View file

@ -1,11 +1,29 @@
#!/usr/bin/python3
import os
import sys
import subprocess
import tempfile
import shutil
"""
Create base Debian filesystem using debootstrap
import osbuild.api
This stage uses debootstrap to create a minimal Debian base system.
Similar to how OSBuild uses dnf/rpm for Fedora, this creates the foundation
for Debian-based builds.
Uses the following binaries from the host:
* `debootstrap` to create the base Debian filesystem
* `cp` to copy files to the target tree
This stage will return metadata about the created base system.
"""
import contextlib
import json
import os
import subprocess
import sys
import tempfile
from operator import itemgetter
from osbuild import api
from osbuild.util.mnt import mount
from osbuild.util.runners import create_machine_id_if_needed
def run_debootstrap(suite, target, mirror, arch=None, variant=None, extra_packages=None, apt_proxy=None):
@ -59,6 +77,54 @@ deb {mirror} {suite}-security main
print(f"Created sources.list for {suite}")
def generate_base_metadata(tree, suite, arch):
"""Generate metadata about the created base system"""
# Get dpkg package list (similar to rpm metadata)
try:
cmd = [
"chroot", tree,
"dpkg-query", "-W",
"--showformat=${Package}\t${Version}\t${Architecture}\t${Status}\n"
]
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
packages = []
for line in result.stdout.strip().split('\n'):
if line.strip():
parts = line.split('\t')
if len(parts) >= 4 and 'installed' in parts[3]:
packages.append({
"name": parts[0],
"version": parts[1],
"architecture": parts[2],
"status": parts[3]
})
packages = sorted(packages, key=itemgetter("name"))
return {
"base_system": {
"suite": suite,
"architecture": arch,
"method": "debootstrap"
},
"packages": packages
}
except subprocess.CalledProcessError as e:
print(f"Warning: Could not generate package metadata: {e}")
return {
"base_system": {
"suite": suite,
"architecture": arch,
"method": "debootstrap"
},
"packages": []
}
def main(tree, options):
"""Main function for debootstrap stage"""
@ -78,16 +144,14 @@ def main(tree, options):
print("No mirror specified for debootstrap")
return 1
# Create temporary directory for debootstrap
with tempfile.TemporaryDirectory() as temp_dir:
print(f"Creating base Debian filesystem in {temp_dir}")
print(f"Creating base Debian filesystem: {suite} from {mirror}")
# Run debootstrap
if not run_debootstrap(suite, temp_dir, mirror, arch, variant, extra_packages, apt_proxy):
# Run debootstrap directly into the target tree
if not run_debootstrap(suite, tree, mirror, arch, variant, extra_packages, apt_proxy):
return 1
# Set up apt sources
setup_apt_sources(temp_dir, suite, mirror)
setup_apt_sources(tree, suite, mirror)
# Configure apt proxy if specified
if apt_proxy:
@ -95,28 +159,30 @@ def main(tree, options):
proxy_config = f"""Acquire::http::Proxy "{apt_proxy}";
Acquire::https::Proxy "{apt_proxy}";
"""
proxy_file = os.path.join(temp_dir, "etc/apt/apt.conf.d/99proxy")
proxy_file = os.path.join(tree, "etc/apt/apt.conf.d/99proxy")
os.makedirs(os.path.dirname(proxy_file), exist_ok=True)
with open(proxy_file, "w") as f:
f.write(proxy_config)
# Copy files to target tree
print(f"Copying filesystem to target tree: {tree}")
# Mount essential filesystems for package operations (similar to rpm stage)
for source in ("/dev", "/sys", "/proc"):
target = os.path.join(tree, source.lstrip("/"))
os.makedirs(target, exist_ok=True)
mount(source, target, ro=False)
# Ensure target directory exists
os.makedirs(tree, exist_ok=True)
# Create /dev/fd symlink
os.symlink("/proc/self/fd", f"{tree}/dev/fd")
# Copy all files from temp directory to target
for item in os.listdir(temp_dir):
src = os.path.join(temp_dir, item)
dst = os.path.join(tree, item)
# Generate metadata about the created system
try:
metadata = generate_base_metadata(tree, suite, arch)
api.metadata(metadata)
except Exception as e:
print(f"Warning: Could not generate metadata: {e}")
if os.path.isdir(src):
if os.path.exists(dst):
shutil.rmtree(dst)
shutil.copytree(src, dst)
else:
shutil.copy2(src, dst)
# Remove random seed if it exists (like rpm stage does)
with contextlib.suppress(FileNotFoundError):
os.unlink(f"{tree}/var/lib/systemd/random-seed")
print("Base Debian filesystem created successfully")
return 0