diff options
Diffstat (limited to 'scripts/image-build')
-rwxr-xr-x | scripts/image-build/build-vyos-image | 32 | ||||
-rw-r--r-- | scripts/image-build/raw_image.py | 93 |
2 files changed, 93 insertions, 32 deletions
diff --git a/scripts/image-build/build-vyos-image b/scripts/image-build/build-vyos-image index d969c157..3275c5de 100755 --- a/scripts/image-build/build-vyos-image +++ b/scripts/image-build/build-vyos-image @@ -367,6 +367,11 @@ if __name__ == "__main__": shutil.copytree("data/live-build-config/", lb_config_dir) os.makedirs(lb_config_dir, exist_ok=True) + ## Secure Boot - Copy public Keys to image + sb_certs = 'data/certificates' + if os.path.isdir(sb_certs): + shutil.copytree(sb_certs, f'{lb_config_dir}/includes.chroot/var/lib/shim-signed/mok') + # Switch to the build directory, this is crucial for the live-build work # because the efective build config files etc. are there. # @@ -611,33 +616,34 @@ DOCUMENTATION_URL="{build_config['documentation_url']}" ## Configure live-build lb_config_tmpl = jinja2.Template(""" lb config noauto \ + --no-color \ --apt-indices false \ - --apt-options "--yes -oAPT::Get::allow-downgrades=true" \ + --apt-options "--yes" \ --apt-recommends false \ - --architecture {{architecture}} \ - --archive-areas {{debian_archive_areas}} \ + --architecture "{{architecture}}" \ + --archive-areas "{{debian_archive_areas}}" \ --backports true \ --binary-image iso-hybrid \ --bootappend-live "boot=live components hostname=vyos username=live nopersistence noautologin nonetworking union=overlay console=ttyS0,115200 console=tty0 net.ifnames=0 biosdevname=0" \ --bootappend-live-failsafe "live components memtest noapic noapm nodma nomce nolapic nomodeset nosmp nosplash vga=normal console=ttyS0,115200 console=tty0 net.ifnames=0 biosdevname=0" \ - --bootloaders {{bootloaders}} \ - --checksums 'sha256 md5' \ + --bootloaders "{{bootloaders}}" \ + --checksums "sha256" \ --chroot-squashfs-compression-type "{{squashfs_compression_type}}" \ --debian-installer none \ --debootstrap-options "--variant=minbase --exclude=isc-dhcp-client,isc-dhcp-common,ifupdown --include=apt-utils,ca-certificates,gnupg2,linux-kbuild-6.1" \ - --distribution {{debian_distribution}} \ + --distribution "{{debian_distribution}}" \ --firmware-binary false \ --firmware-chroot false \ --iso-application "VyOS" \ --iso-publisher "{{build_by}}" \ --iso-volume "VyOS" \ - --linux-flavours {{kernel_flavor}} \ - --linux-packages linux-image-{{kernel_version}} \ - --mirror-binary {{debian_mirror}} \ - --mirror-binary-security {{debian_security_mirror}} \ - --mirror-bootstrap {{debian_mirror}} \ - --mirror-chroot {{debian_mirror}} \ - --mirror-chroot-security {{debian_security_mirror}} \ + --linux-flavours "{{kernel_flavor}}" \ + --linux-packages "linux-image-{{kernel_version}}" \ + --mirror-binary "{{debian_mirror}}" \ + --mirror-binary-security "{{debian_security_mirror}}" \ + --mirror-bootstrap "{{debian_mirror}}" \ + --mirror-chroot "{{debian_mirror}}" \ + --mirror-chroot-security "{{debian_security_mirror}}" \ --security true \ --updates true \ --utc-time true diff --git a/scripts/image-build/raw_image.py b/scripts/image-build/raw_image.py index d850eead..a88ed020 100644 --- a/scripts/image-build/raw_image.py +++ b/scripts/image-build/raw_image.py @@ -63,22 +63,38 @@ class BuildContext: return self - def __exit__(self, exc_type, exc_value, exc_tb): + def __exit__(self, exc_type, exc_value, traceback): print(f"I: Tearing down the raw image build environment in {self.work_dir}") - cmd(f"""umount {self.squash_dir}/dev/""") - cmd(f"""umount {self.squash_dir}/proc/""") - cmd(f"""umount {self.squash_dir}/sys/""") - - cmd(f"umount {self.squash_dir}/boot/efi") - cmd(f"umount {self.squash_dir}/boot") - - cmd(f"""umount {self.squash_dir}""") - cmd(f"""umount {self.iso_dir}""") - cmd(f"""umount {self.raw_dir}""") - cmd(f"""umount {self.efi_dir}""") + for mount in [ + f"{self.squash_dir}/dev/", + f"{self.squash_dir}/proc/", + f"{self.squash_dir}/sys/", + f"{self.squash_dir}/boot/efi", + f"{self.squash_dir}/boot", + f"{self.squash_dir}", + f"{self.iso_dir}", + f"{self.raw_dir}", + f"{self.efi_dir}" + ]: + if os.path.ismount(mount): + try: + cmd(f"umount {mount}") + except Exception as e: + print(f"W: Failed to umount {mount}: {e}") + + # Remove kpartx mappings if self.loop_device: - cmd(f"""losetup -d {self.loop_device}""") + mapper_base = os.path.basename(self.loop_device) + try: + cmd(f"kpartx -d {self.loop_device}") + except Exception as e: + print(f"W: Failed to remove kpartx mappings for {mapper_base}: {e}") + + try: + cmd(f"losetup -d {self.loop_device}") + except Exception as e: + print(f"W: Failed to detach loop device {self.loop_device}: {e}") def create_disk(path, size): cmd(f"""qemu-img create -f raw "{path}" {size}G""") @@ -106,14 +122,23 @@ def setup_loop_device(con, raw_file): def mount_image(con): import vyos.system.disk - from subprocess import Popen, PIPE, STDOUT - from re import match + try: + root = con.disk_details.partition['root'] + efi = con.disk_details.partition['efi'] + except (AttributeError, KeyError): + raise RuntimeError("E: No valid root or EFI partition found in disk details") + + vyos.system.disk.filesystem_create(efi, 'efi') + vyos.system.disk.filesystem_create(root, 'ext4') - vyos.system.disk.filesystem_create(con.disk_details.partition['efi'], 'efi') - vyos.system.disk.filesystem_create(con.disk_details.partition['root'], 'ext4') + print(f"I: Mounting root: {root} to {con.raw_dir}") + cmd(f"mount -t ext4 {root} {con.raw_dir}") + cmd(f"mount -t vfat {efi} {con.efi_dir}") - cmd(f"mount -t ext4 {con.disk_details.partition['root']} {con.raw_dir}") - cmd(f"mount -t vfat {con.disk_details.partition['efi']} {con.efi_dir}") + if not os.path.ismount(con.efi_dir): + cmd(f"mount -t vfat {con.disk_details.partition['efi']} {con.efi_dir}") + else: + print(f"I: {con.disk_details.partition['efi']} already mounted on {con.efi_dir}") def install_image(con, version): from glob import glob @@ -205,6 +230,36 @@ def create_raw_image(build_config, iso_file, work_dir): create_disk(raw_file, build_config["disk_size"]) setup_loop_device(con, raw_file) disk_details = parttable_create(con.loop_device, (int(build_config["disk_size"]) - 1) * 1024 * 1024) + + # Map partitions using kpartx + print("I: Mapping partitions using kpartx...") + cmd(f"kpartx -av {con.loop_device}") + cmd("udevadm settle") + + + # Detect mapped partitions + from glob import glob + import time + + mapper_base = os.path.basename(con.loop_device).replace("/dev/", "") + mapped_parts = sorted(glob(f"/dev/mapper/{mapper_base}p*")) + + if not mapped_parts: + raise RuntimeError(f"E: No partitions were found in /dev/mapper for {mapper_base}") + + print(f"I: Found mapped partitions: {mapped_parts}") + + if len(mapped_parts) == 2: + # Assume [0] = EFI, [1] = root + disk_details.partition['efi'] = mapped_parts[0] + disk_details.partition['root'] = mapped_parts[1] + elif len(mapped_parts) >= 3: + # Common layout: [1] = EFI, [2] = root (skip 0 if it's BIOS boot) + disk_details.partition['efi'] = mapped_parts[1] + disk_details.partition['root'] = mapped_parts[2] + else: + raise RuntimeError(f"E: Unexpected partition layout: {mapped_parts}") + con.disk_details = disk_details mount_image(con) install_image(con, version) |