Files
scale-build/scale_build/bootstrap/bootstrapdir.py
sonicaj 8e86e2d981 NAS-137225 / 26.04 / Fix scale build for trixie (#925)
* Trixie related changes for scale-build

* Point to HM mirrors

* Update apt preferences for trixie

* Update debootstrap changes for trixie

* Minor fix

* Remove python3 package

* Remove mandatory explicit dep

* Use openjdk-21-jdk for kernel

* Update passwd

* There is no need for custom openssl now

* Move from libssl3 to libssl3t64

* Remove util-linux from build manifest

* Set env variable for spdk

* Don't buidl spdk for now

* ipmctl is not available in stable

* Remove legacy sysv unit stuff

* Comment out netdata for now

* Small umount fix

* Also umount efivars

* Update build manifest to reflect updated branches

* Remove nfs entry from mtree

* Make sure to umount efivars

* Properly have apt sources fixed in update image

* Pull in grub2-common

* Add netdata mirror

* Fix url

* Make sure corepack is non-interactive

* Update netdata groups

* Fix efivars mounting

* Properly use clean_mounts

* Add fixme for netdata

* Properly comment out spdk explicit deps

* Remove grub-efi-amd64-signed from iso

* Make sure efivarfs is definitely mounted

* Bring in isc-dhcp-client for now

* Revert "Bring in isc-dhcp-client for now"

This reverts commit 259ffebba5.

* Only try to umount efivarfs if host is actually efi based

* Update repo's branches
2025-09-19 21:55:20 +05:00

222 lines
7.6 KiB
Python

import logging
import os
import shutil
from scale_build.clean import clean_packages
from scale_build.utils.manifest import get_manifest, get_apt_repos
from scale_build.utils.paths import BUILDER_DIR, CHROOT_BASEDIR, REFERENCE_FILES, REFERENCE_FILES_DIR
from scale_build.utils.run import run
from .cache import CacheMixin
from .hash import HashMixin
from .utils import get_apt_preferences
logger = logging.getLogger(__name__)
class BootstrapDir(CacheMixin, HashMixin):
def __init__(self):
self.logger = logger
self.chroot_basedir = CHROOT_BASEDIR
def setup(self):
self.clean_setup()
try:
self.setup_impl()
finally:
self.clean_setup()
def debootstrap_debian(self):
manifest = get_manifest()
# Debootstrap needs binary format key, convert ASCII-armored to binary
keyring_path = os.path.join(BUILDER_DIR, 'keys/truenas.gpg')
binary_keyring = '/tmp/truenas-binary.gpg'
# Convert ASCII-armored key to binary format for debootstrap
run(['sh', '-c', f'gpg --dearmor < {keyring_path} > {binary_keyring}'])
run(
['debootstrap'] + self.deopts + [
'--keyring', binary_keyring,
manifest['debian_release'],
self.chroot_basedir, get_apt_repos(check_custom=True)['url']
]
)
def setup_impl(self):
if self.mirror_cache_intact:
# Mirror cache is intact, we do not need to re-create the bootstrap directory
self.logger.debug('Basechroot cache is intact and does not need to be changed')
return
apt_repos = get_apt_repos(check_custom=True)
self.debootstrap_debian()
self.setup_mounts()
self.logger.debug('Updating apt preferences')
apt_path = os.path.join(self.chroot_basedir, 'etc/apt')
apt_sources_path = os.path.join(apt_path, 'sources.list')
# Set up apt preferences
with open(os.path.join(apt_path, 'preferences'), 'w') as f:
f.write(get_apt_preferences())
# Create keyrings directory in chroot
keyring_dir = os.path.join(self.chroot_basedir, 'etc/apt/keyrings')
os.makedirs(keyring_dir, exist_ok=True)
# Copy TrueNAS key to chroot keyrings
truenas_key = os.path.join(keyring_dir, 'truenas-archive.gpg')
shutil.copy(os.path.join(BUILDER_DIR, 'keys/truenas.gpg'), truenas_key)
# Build sources.list with signed-by directives
# Main repository
apt_sources = [
'deb [signed-by=/etc/apt/keyrings/truenas-archive.gpg] '
f'{apt_repos["url"]} {apt_repos["distribution"]} {apt_repos["components"]}'
]
# Add additional repos
for repo in apt_repos['additional']:
self.logger.debug('Adding additional repo: %r', repo['url'])
if repo.get('key'):
# Copy specific key to chroot keyrings
key_name = os.path.basename(repo['key'])
shutil.copy(os.path.join(BUILDER_DIR, repo['key']), os.path.join(keyring_dir, key_name))
# Add repo with its specific key
apt_sources.append(
f'deb [signed-by=/etc/apt/keyrings/{key_name}] '
f'{repo["url"]} {repo["distribution"]} {repo["component"]}'
)
else:
# Repo without specific key - uses TrueNAS key
apt_sources.append(
f'deb [signed-by=/etc/apt/keyrings/truenas-archive.gpg] '
f'{repo["url"]} {repo["distribution"]} {repo["component"]}'
)
# Write initial sources.list
with open(apt_sources_path, 'w') as f:
f.write('\n'.join(apt_sources))
# Update and upgrade
run(['chroot', self.chroot_basedir, 'apt', 'update'])
run(['chroot', self.chroot_basedir, 'apt', 'upgrade', '-y'])
if self.extra_packages_to_install:
run(['chroot', self.chroot_basedir, 'apt', 'install', '-y'] + self.extra_packages_to_install)
installed_packages = self.get_packages()
self.after_extra_packages_installation_steps()
# Put our local package up at the top of the food chain
apt_sources.insert(0, 'deb [trusted=yes] file:/packages /')
with open(apt_sources_path, 'w') as f:
f.write('\n'.join(apt_sources))
self.clean_mounts()
self.save_build_cache(installed_packages)
def after_extra_packages_installation_steps(self):
pass
@property
def extra_packages_to_install(self):
raise NotImplementedError
@property
def deopts(self):
raise NotImplementedError
def setup_mounts(self):
run(['mount', 'proc', os.path.join(self.chroot_basedir, 'proc'), '-t', 'proc'])
run(['mount', 'sysfs', os.path.join(self.chroot_basedir, 'sys'), '-t', 'sysfs'])
def clean_mounts(self):
for command in (
['umount', '-f', os.path.join(self.chroot_basedir, 'proc')],
['umount', '-f', os.path.join(self.chroot_basedir, 'sys')],
):
run(command, check=False, log=False)
def clean_setup(self):
self.clean_mounts()
if os.path.exists(self.chroot_basedir):
shutil.rmtree(self.chroot_basedir)
class RootfsBootstrapDir(BootstrapDir):
@property
def deopts(self):
return []
@property
def extra_packages_to_install(self):
return []
@property
def cache_filename(self):
return 'basechroot-rootfs.squashfs'
def debootstrap_debian(self):
manifest = get_manifest()
# Debootstrap needs binary format key, convert ASCII-armored to binary
keyring_path = os.path.join(BUILDER_DIR, 'keys/truenas.gpg')
binary_keyring = '/tmp/truenas-binary.gpg'
# Convert ASCII-armored key to binary format for debootstrap
run(['sh', '-c', f'gpg --dearmor < {keyring_path} > {binary_keyring}'])
run(
['debootstrap'] + self.deopts + [
'--foreign', '--keyring', binary_keyring,
manifest['debian_release'],
self.chroot_basedir, get_apt_repos(check_custom=True)['url']
]
)
for reference_file in REFERENCE_FILES:
shutil.copyfile(
os.path.join(REFERENCE_FILES_DIR, reference_file),
os.path.join(self.chroot_basedir, reference_file)
)
run(['chroot', self.chroot_basedir, '/debootstrap/debootstrap', '--second-stage'])
# For some reason debootstrap --second stage is removing ftp group, it does get added back by some
# other package later on but currently it results in base cache not reflecting reference files
# so we add it back here
# FIXME: Figure out why debootstrap --second-stage is removing ftp group
shutil.copyfile(os.path.join(REFERENCE_FILES_DIR, 'etc/group'), os.path.join(self.chroot_basedir, 'etc/group'))
class PackageBootstrapDir(RootfsBootstrapDir):
@property
def extra_packages_to_install(self):
return ['build-essential', 'dh-make', 'devscripts', 'fakeroot']
@property
def cache_filename(self):
return 'basechroot-package.squashfs'
def after_extra_packages_installation_steps(self):
if self.installed_packages_in_cache_changed:
clean_packages()
class CdromBootstrapDirectory(BootstrapDir):
@property
def deopts(self):
return ['--components=main,contrib,nonfree', '--variant=minbase', '--include=systemd-sysv,gnupg']
@property
def extra_packages_to_install(self):
return []
@property
def cache_filename(self):
return 'basechroot-cdrom.squashfs'