Merge branch 'better-local-experience' into ubuntu/master

This commit is contained in:
michael.hudson@canonical.com 2026-03-16 10:50:17 +13:00
commit 5e4e502c76
No known key found for this signature in database
GPG Key ID: 80E627A0AB757E23
14 changed files with 496 additions and 49 deletions

12
debian/changelog vendored
View File

@ -1,8 +1,16 @@
livecd-rootfs (26.04.24) resolute; urgency=medium
livecd-rootfs (26.04.24) UNRELEASED; urgency=medium
[ Allen Abraham ]
* Added a hook to produce a working minimal Ubuntu image using imagecraft
-- Allen Abraham <allen.abraham@canonical.com> Tue, 03 Mar 2026 10:54:22 -0500
[ Michael Hudson-Doyle ]
* Various quality of life improvements for hacking on livecd-rootfs:
- Add a "ubuntu-test-iso" project that builds a not very useful ISO in 2-5 minutes.
- Add a build-livefs script that takes care of copying the auto scripts and
invoking lb clean/config/build with the right environment.
- Add a build-livefs-lxd script to run the above script in a lxd vm.
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Mon, 23 Feb 2026 15:02:42 +1300
livecd-rootfs (26.04.23) resolute; urgency=medium

1
debian/livecd-rootfs.links vendored Normal file
View File

@ -0,0 +1 @@
usr/share/livecd-rootfs/live-build/build-livefs usr/bin/build-livefs

View File

@ -375,7 +375,7 @@ EOF
(cd chroot && find usr/share/doc -maxdepth 1 -type d | xargs du -s | sort -nr)
echo END docdirs
/usr/share/livecd-rootfs/minimize-manual chroot
${LIVECD_ROOTFS_ROOT}/minimize-manual chroot
clean_debian_chroot
fi

View File

@ -1,6 +1,8 @@
#!/bin/bash
set -e
LIVECD_ROOTFS_ROOT=${LIVECD_ROOTFS_ROOT:-/usr/share/livecd-rootfs}
case $ARCH:$SUBARCH in
amd64:|amd64:generic|amd64:intel-iot|\
arm64:|arm64:generic|arm64:raspi|arm64:snapdragon|arm64:nvidia|\
@ -47,12 +49,12 @@ if [ -z "$MIRROR" ]; then
fi
mkdir -p config
cp -af /usr/share/livecd-rootfs/live-build/functions config/functions
cp -af /usr/share/livecd-rootfs/live-build/lb_*_layered config/
cp -af /usr/share/livecd-rootfs/live-build/snap-seed-parse.py config/snap-seed-parse
cp -af /usr/share/livecd-rootfs/live-build/snap-seed-missing-providers.py config/snap-seed-missing-providers
cp -af /usr/share/livecd-rootfs/live-build/expand-task config/expand-task
cp -af /usr/share/livecd-rootfs/live-build/squashfs-exclude-files config/
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/functions config/functions
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/lb_*_layered config/
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/snap-seed-parse.py config/snap-seed-parse
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/snap-seed-missing-providers.py config/snap-seed-missing-providers
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/expand-task config/expand-task
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/squashfs-exclude-files config/
mkdir -p config/package-lists
@ -390,7 +392,7 @@ if [ -z "${IMAGEFORMAT:-}" ]; then
;;
esac
;;
ubuntu-server:live|ubuntu-mini-iso:|ubuntu-core-installer:*)
ubuntu-server:live|ubuntu-mini-iso:|ubuntu-test-iso:|ubuntu-core-installer:*)
IMAGEFORMAT=plain
;;
esac
@ -426,7 +428,7 @@ case $IMAGEFORMAT in
ubuntu-server:live|ubuntu-core-installer:*)
touch config/universe-enabled
;;
ubuntu-mini-iso:)
ubuntu-mini-iso:|ubuntu-test-iso:)
fs=none
;;
*)
@ -636,7 +638,7 @@ case $PROJECT in
esac
case $PROJECT in
ubuntu-mini-iso)
ubuntu-mini-iso|ubuntu-test-iso)
COMPONENTS='main'
;;
edubuntu|ubuntu-budgie|ubuntucinnamon|ubuntukylin)
@ -653,15 +655,24 @@ case $SUBPROJECT in
;;
esac
if ! [ -e config/germinate-output/structure ]; then
echo "Running germinate..."
if [ -n "$COMPONENTS" ]; then
GERMINATE_ARG="-c $(echo $COMPONENTS | sed -e's/ \+/,/g')"
fi
(cd config/germinate-output && germinate --no-rdepends --no-installer \
-S $SEEDMIRROR -m $MIRROR -d $SUITE,$SUITE-updates \
-s $FLAVOUR.$SUITE $GERMINATE_ARG -a ${ARCH_VARIANT:-$ARCH})
fi
case $PROJECT in
ubuntu-test-iso)
# ubuntu-test-iso uses only add_package (not add_task) and has no
# pool, so germinate output is never needed.
touch config/germinate-output/structure
;;
*)
if ! [ -e config/germinate-output/structure ]; then
echo "Running germinate..."
if [ -n "$COMPONENTS" ]; then
GERMINATE_ARG="-c $(echo $COMPONENTS | sed -e's/ \+/,/g')"
fi
(cd config/germinate-output && germinate --no-rdepends --no-installer \
-S $SEEDMIRROR -m $MIRROR -d $SUITE,$SUITE-updates \
-s $FLAVOUR.$SUITE $GERMINATE_ARG -a ${ARCH_VARIANT:-$ARCH})
fi
;;
esac
# ISO build configuration. These defaults are overridden per-project below.
#
@ -674,6 +685,9 @@ MAKE_ISO=no
# - "server-ship-live" for Ubuntu Server (includes server-specific packages)
# - "" (empty) for images without a pool, like Ubuntu Core Installer
POOL_SEED_NAME=ship-live
# SQUASHFS_COMP: compression algorithm for squashfs images. lz4 is ~10x
# faster than xz and useful for test builds that don't need small images.
SQUASHFS_COMP=xz
# Common functionality for layered desktop images
common_layered_desktop_image() {
@ -804,7 +818,7 @@ do_layered_desktop_image() {
DEFAULT_KERNEL="linux-$KERNEL_FLAVOURS"
if [ "$LOCALE_SUPPORT" != none ]; then
/usr/share/livecd-rootfs/checkout-translations-branch \
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
https://git.launchpad.net/subiquity po \
config/catalog-translations
fi
@ -1124,7 +1138,7 @@ case $PROJECT in
NO_SQUASHFS_PASSES=ubuntu-server-minimal.ubuntu-server.installer.$flavor.netboot
DEFAULT_KERNEL="$kernel_metapkg"
/usr/share/livecd-rootfs/checkout-translations-branch \
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
https://git.launchpad.net/subiquity po config/catalog-translations
;;
*)
@ -1142,7 +1156,7 @@ case $PROJECT in
# created in ubuntu-core-installer/hooks/05-prepare-image.binary, which
# subiquity knows how to install.
if [ ${SUBPROJECT} == "desktop" ]; then
cp /usr/share/livecd-rootfs/live-build/${PROJECT}/ubuntu-core-desktop-24-amd64.model-assertion config/
cp ${LIVECD_ROOTFS_ROOT}/live-build/${PROJECT}/ubuntu-core-desktop-24-amd64.model-assertion config/
fi
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
PASSES_TO_LAYERS=true
@ -1156,7 +1170,7 @@ case $PROJECT in
USE_BRIDGE_KERNEL=false
DEFAULT_KERNEL="snap:pc-kernel"
/usr/share/livecd-rootfs/checkout-translations-branch \
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
https://git.launchpad.net/subiquity po config/catalog-translations
;;
@ -1179,6 +1193,22 @@ case $PROJECT in
esac
;;
ubuntu-test-iso)
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
KERNEL_FLAVOURS=virtual
BINARY_REMOVE_LINUX=false
MAKE_ISO=yes
POOL_SEED_NAME=
SQUASHFS_COMP=lz4
PASSES_TO_LAYERS=true
add_package base linux-$KERNEL_FLAVOURS
add_package base.live casper
case $ARCH in
amd64) ;;
*) echo "ubuntu-test-iso only supports amd64"; exit 1 ;;
esac
;;
ubuntu-base|ubuntu-oci)
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
;;
@ -1278,7 +1308,7 @@ case $SUBPROJECT in
# and a variety of things fail without it.
add_package install tzdata
cp -af /usr/share/livecd-rootfs/live-build/make-lxd-metadata.py config/make-lxd-metadata
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/make-lxd-metadata.py config/make-lxd-metadata
;;
esac
@ -1403,11 +1433,13 @@ echo "LB_CHROOT_HOOKS=\"$CHROOT_HOOKS\"" >> config/chroot
echo "SUBPROJECT=\"${SUBPROJECT:-}\"" >> config/chroot
echo "LB_DISTRIBUTION=\"$SUITE\"" >> config/chroot
echo "IMAGEFORMAT=\"$IMAGEFORMAT\"" >> config/chroot
echo "LIVECD_ROOTFS_ROOT=\"$LIVECD_ROOTFS_ROOT\"" >> config/common
if [ -n "$PASSES" ]; then
echo "PASSES=\"$PASSES\"" >> config/common
fi
echo "MAKE_ISO=\"$MAKE_ISO\"" >> config/common
echo "POOL_SEED_NAME=\"$POOL_SEED_NAME\"" >> config/common
echo "SQUASHFS_COMP=\"$SQUASHFS_COMP\"" >> config/common
if [ -n "$NO_SQUASHFS_PASSES" ]; then
echo "NO_SQUASHFS_PASSES=\"$NO_SQUASHFS_PASSES\"" >> config/common
fi
@ -1443,7 +1475,7 @@ rm -fv /etc/ssl/private/ssl-cert-snakeoil.key \
EOF
case $PROJECT in
ubuntu-cpc|ubuntu-core|ubuntu-base|ubuntu-oci|ubuntu-wsl|ubuntu-mini-iso)
ubuntu-cpc|ubuntu-core|ubuntu-base|ubuntu-oci|ubuntu-wsl|ubuntu-mini-iso|ubuntu-test-iso)
# ubuntu-cpc gets this added in 025-create-groups.chroot, and we do
# not want this group in projects that are effectively just chroots
;;
@ -1531,11 +1563,11 @@ fi
case $PROJECT:${SUBPROJECT:-} in
ubuntu-cpc:*|ubuntu-server:live|ubuntu:desktop-preinstalled| \
ubuntu-wsl:*|ubuntu-mini-iso:*|ubuntu:|ubuntu:dangerous|ubuntu-oem:*| \
ubuntu-wsl:*|ubuntu-mini-iso:*|ubuntu-test-iso:*|ubuntu:|ubuntu:dangerous|ubuntu-oem:*| \
ubuntustudio:*|edubuntu:*|ubuntu-budgie:*|ubuntucinnamon:*|xubuntu:*| \
ubuntukylin:*|ubuntu-mate:*|ubuntu-core-installer:*|lubuntu:*)
# Ensure that most things e.g. includes.chroot are copied as is
for entry in /usr/share/livecd-rootfs/live-build/${PROJECT}/*; do
for entry in ${LIVECD_ROOTFS_ROOT}/live-build/${PROJECT}/*; do
case $entry in
*hooks*)
# But hooks are shared across the projects with symlinks
@ -1570,11 +1602,11 @@ esac
case $PROJECT in
ubuntu-oem|ubuntustudio|edubuntu|ubuntu-budgie|ubuntucinnamon| \
xubuntu|ubuntukylin|ubuntu-mate|lubuntu)
cp -af /usr/share/livecd-rootfs/live-build/ubuntu/includes.chroot \
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/ubuntu/includes.chroot \
config/includes.chroot
LIVE_LAYER=${LIVE_PREFIX}live
cp -af /usr/share/livecd-rootfs/live-build/ubuntu/includes.chroot.minimal.standard.live \
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/ubuntu/includes.chroot.minimal.standard.live \
config/includes.chroot.$LIVE_LAYER
if [ $PROJECT != ubuntu-oem ]; then
@ -1590,7 +1622,7 @@ esac
case $SUBPROJECT in
buildd)
cp -af /usr/share/livecd-rootfs/live-build/buildd/* config/
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/buildd/* config/
;;
esac
@ -1614,7 +1646,7 @@ if [ "$EXTRA_PPAS" ]; then
extra_ppa=${extra_ppa%:*}
;;
esac
extra_ppa_fingerprint="$(/usr/share/livecd-rootfs/get-ppa-fingerprint "$extra_ppa")"
extra_ppa_fingerprint="$(${LIVECD_ROOTFS_ROOT}/get-ppa-fingerprint "$extra_ppa")"
cat >> config/archives/extra-ppas.list.chroot <<EOF
deb https://ppa.launchpadcontent.net/$extra_ppa/ubuntu @DISTRIBUTION@ main
@ -1704,8 +1736,19 @@ fi
if [ "${MAKE_ISO}" = "yes" ]; then
# XXX should pass --build-type here.
/usr/share/livecd-rootfs/live-build/gen-iso-ids \
${LIVECD_ROOTFS_ROOT}/live-build/gen-iso-ids \
--project $PROJECT ${SUBPROJECT:+--subproject $SUBPROJECT} \
--arch $ARCH ${SUBARCH:+--subarch $SUBARCH} ${NOW+--serial $NOW} \
--output-dir config/iso-ids/
fi
if [ -n "$http_proxy" ]; then
mkdir -p /etc/systemd/system/snapd.service.d/
cat > /etc/systemd/system/snapd.service.d/snap_proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=${http_proxy}"
Environment="HTTPS_PROXY=${http_proxy}"
EOF
systemctl daemon-reload
systemctl restart snapd.service
fi

218
live-build/build-livefs Executable file
View File

@ -0,0 +1,218 @@
#!/usr/bin/python3
import configparser
import os
import pathlib
import platform
import subprocess
import click
_CONFIG_FILE = pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"
def _read_config() -> dict[str, str]:
"""Read default values from the user config file if it exists.
The config file uses INI format with a [defaults] section, e.g.:
[defaults]
http-proxy = http://squid.internal:3128/
mirror = http://ftpmaster.internal/ubuntu/
"""
cp = configparser.ConfigParser()
cp.read(_CONFIG_FILE)
return dict(cp["defaults"]) if "defaults" in cp else {}
_MACHINE_TO_ARCH = {
"x86_64": "amd64",
"aarch64": "arm64",
"ppc64le": "ppc64el",
"s390x": "s390x",
"riscv64": "riscv64",
"armv7l": "armhf",
}
def _default_arch():
machine = platform.machine()
try:
return _MACHINE_TO_ARCH[machine]
except KeyError:
raise click.UsageError(
f"Cannot determine default arch for machine {machine!r}; use --arch"
)
@click.command()
@click.option(
"--work-dir",
default=".",
type=click.Path(file_okay=False, path_type=pathlib.Path),
help="Working directory for the build (default: current directory)",
)
@click.option("--project", required=True, help="Project name (e.g. ubuntu, ubuntu-cpc)")
@click.option("--suite", required=True, help="Ubuntu suite/series (e.g. noble)")
@click.option("--arch", default=None, help="Target architecture (default: host arch)")
@click.option("--arch-variant", default=None, help="Architecture variant")
@click.option("--subproject", default=None, help="Subproject")
@click.option("--subarch", default=None, help="Sub-architecture")
@click.option("--channel", default=None, help="Channel")
@click.option(
"--image-target",
"image_targets",
multiple=True,
help="Image target (may be repeated)",
)
@click.option("--repo-snapshot-stamp", default=None, help="Repository snapshot stamp")
@click.option(
"--snapshot-service-timestamp", default=None, help="Snapshot service timestamp"
)
@click.option("--cohort-key", default=None, help="Cohort key")
@click.option("--datestamp", default=None, help="Datestamp (sets NOW)")
@click.option("--image-format", default=None, help="Image format (sets IMAGEFORMAT)")
@click.option(
"--proposed",
is_flag=True,
default=False,
help="Enable proposed pocket (sets PROPOSED=1)",
)
@click.option(
"--extra-ppa", "extra_ppas", multiple=True, help="Extra PPA (may be repeated)"
)
@click.option(
"--extra-snap", "extra_snaps", multiple=True, help="Extra snap (may be repeated)"
)
@click.option("--build-type", default=None, help="Build type")
@click.option(
"--http-proxy",
default=None,
help="HTTP proxy (sets http_proxy, HTTP_PROXY, LB_APT_HTTP_PROXY)",
)
@click.option(
"--mirror",
default=None,
help="Ubuntu archive mirror URL (sets MIRROR)",
)
@click.option(
"--debug", is_flag=True, default=False, help="Enable debug mode (set -x in lb scripts)"
)
def main(
work_dir,
project,
suite,
arch,
arch_variant,
subproject,
subarch,
channel,
image_targets,
repo_snapshot_stamp,
snapshot_service_timestamp,
cohort_key,
datestamp,
image_format,
proposed,
extra_ppas,
extra_snaps,
build_type,
http_proxy,
mirror,
debug,
):
cfg = _read_config()
if http_proxy is None:
http_proxy = cfg.get("http-proxy")
if mirror is None:
mirror = cfg.get("mirror")
if arch is None:
arch = _default_arch()
# Locate auto/ scripts relative to this script, following symlinks.
# Works for: git checkout, installed deb, and /usr/bin/build-livefs symlink.
live_build_dir = pathlib.Path(__file__).resolve().parent
auto_source = live_build_dir / "auto"
# base_env is passed to both lb config and lb build
base_env = {
"PROJECT": project,
"ARCH": arch,
"LIVECD_ROOTFS_ROOT": str(live_build_dir.parent),
}
if arch_variant is not None:
base_env["ARCH_VARIANT"] = arch_variant
if subproject is not None:
base_env["SUBPROJECT"] = subproject
if subarch is not None:
base_env["SUBARCH"] = subarch
if channel is not None:
base_env["CHANNEL"] = channel
if image_targets:
base_env["IMAGE_TARGETS"] = " ".join(image_targets)
if repo_snapshot_stamp is not None:
base_env["REPO_SNAPSHOT_STAMP"] = repo_snapshot_stamp
if snapshot_service_timestamp is not None:
base_env["SNAPSHOT_SERVICE_TIMESTAMP"] = snapshot_service_timestamp
if cohort_key is not None:
base_env["COHORT_KEY"] = cohort_key
if http_proxy is not None:
base_env["http_proxy"] = http_proxy
base_env["HTTP_PROXY"] = http_proxy
base_env["LB_APT_HTTP_PROXY"] = http_proxy
# config_env adds lb-config-only vars on top of base_env
config_env = {
**base_env,
"SUITE": suite,
}
if datestamp is not None:
config_env["NOW"] = datestamp
if image_format is not None:
config_env["IMAGEFORMAT"] = image_format
if proposed:
config_env["PROPOSED"] = "1"
if extra_ppas:
config_env["EXTRA_PPAS"] = " ".join(extra_ppas)
if extra_snaps:
config_env["EXTRA_SNAPS"] = " ".join(extra_snaps)
if build_type is not None:
config_env["BUILD_TYPE"] = build_type
if mirror is not None:
config_env["MIRROR"] = mirror
work_dir = work_dir.resolve()
work_dir.mkdir(parents=True, exist_ok=True)
# Create/replace auto/ symlinks
auto_dir = work_dir / "auto"
auto_dir.mkdir(exist_ok=True)
for script in ("config", "build", "clean"):
link = auto_dir / script
if link.is_symlink() or link.exists():
link.unlink()
link.symlink_to(auto_source / script)
# Write debug.sh if requested
if debug:
debug_dir = work_dir / "local" / "functions"
debug_dir.mkdir(parents=True, exist_ok=True)
(debug_dir / "debug.sh").write_text("set -x\n")
def run(cmd, env_extra):
env = os.environ.copy()
env.update(env_extra)
if os.getuid() != 0:
env_args = [f"{k}={v}" for k, v in env_extra.items()]
cmd = ["sudo", "env"] + env_args + cmd
subprocess.run(cmd, cwd=work_dir, env=env, check=True)
run(["lb", "clean", "--purge"], base_env)
run(["lb", "config"], config_env)
run(["lb", "build"], base_env)
if __name__ == "__main__":
main()

150
live-build/build-livefs-lxd Executable file
View File

@ -0,0 +1,150 @@
#!/usr/bin/env python3
import configparser
import pathlib
import subprocess
import time
import click
_CONFIG_FILE = pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"
def _read_config() -> dict[str, str]:
cp = configparser.ConfigParser()
cp.read(_CONFIG_FILE)
return dict(cp["defaults"]) if "defaults" in cp else {}
@click.command(
context_settings={"ignore_unknown_options": True, "allow_extra_args": True}
)
@click.option("--suite", required=True, help="Ubuntu suite/series (e.g. noble)")
@click.option(
"--vm-name",
default=None,
help="LXD VM name (default: livefs-builder-{suite})",
)
@click.option(
"--http-proxy",
default=None,
help="HTTP proxy URL for apt inside the VM (also read from build-livefs.conf)",
)
@click.argument("extra_args", nargs=-1, type=click.UNPROCESSED)
def main(suite, vm_name, http_proxy, extra_args):
livecd_rootfs_root = pathlib.Path(__file__).resolve().parent.parent
vm_name = vm_name or f"livefs-builder-{suite}"
host_conf = (
pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"
)
if http_proxy is None:
http_proxy = _read_config().get("http-proxy")
result = subprocess.run(["lxc", "info", vm_name], capture_output=True)
if result.returncode != 0:
launch_cmd = [
"lxc", "launch", f"ubuntu-daily:{suite}", vm_name, "--vm",
"--config", "limits.cpu=4",
"--config", "limits.memory=8GiB",
"--device", "root,size=100GiB",
]
user_data = "#cloud-config\npackage_update: true\n"
if http_proxy is not None:
user_data += (
"apt:\n"
f" http_proxy: {http_proxy}\n"
f" https_proxy: {http_proxy}\n"
)
launch_cmd += ["--config", f"user.user-data={user_data}"]
subprocess.run(launch_cmd, check=True)
device_info = subprocess.run(
["lxc", "config", "device", "show", vm_name],
capture_output=True,
text=True,
check=True,
).stdout
if "livecd-rootfs" not in device_info:
subprocess.run(
[
"lxc",
"config",
"device",
"add",
vm_name,
"livecd-rootfs",
"disk",
f"source={livecd_rootfs_root}",
"path=/srv/livecd-rootfs",
],
check=True,
)
info = subprocess.run(
["lxc", "info", vm_name], capture_output=True, text=True, check=True
).stdout
if "Status: STOPPED" in info:
subprocess.run(["lxc", "start", vm_name], check=True)
for _ in range(30):
result = subprocess.run(
["lxc", "exec", vm_name, "--", "true"], capture_output=True
)
if result.returncode == 0:
break
time.sleep(2)
else:
raise click.ClickException(f"VM {vm_name!r} did not become ready in time")
subprocess.run(
["lxc", "exec", vm_name, "--", "cloud-init", "status", "--wait"], check=True
)
subprocess.run(
["lxc", "exec", vm_name, "--", "apt-get", "install", "-y", "livecd-rootfs"],
check=True,
)
if host_conf.exists():
subprocess.run(
[
"lxc",
"exec",
vm_name,
"--",
"mkdir",
"-p",
"/root/.config/livecd-rootfs",
],
check=True,
)
subprocess.run(
[
"lxc",
"file",
"push",
str(host_conf),
f"{vm_name}/root/.config/livecd-rootfs/build-livefs.conf",
],
check=True,
)
subprocess.run(
[
"lxc",
"exec",
vm_name,
"--",
"/srv/livecd-rootfs/live-build/build-livefs",
"--suite",
suite,
*extra_args,
],
check=True,
)
if __name__ == "__main__":
main()

View File

@ -188,8 +188,8 @@ setup_mountpoint() {
mount sysfs-live -t sysfs "$mountpoint/sys"
mount securityfs -t securityfs "$mountpoint/sys/kernel/security"
# Provide more up to date apparmor features, matching target kernel
mount -o bind /usr/share/livecd-rootfs/live-build/apparmor/generic "$mountpoint/sys/kernel/security/apparmor/features/"
mount -o bind /usr/share/livecd-rootfs/live-build/seccomp/generic.actions_avail "$mountpoint/proc/sys/kernel/seccomp/actions_avail"
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/generic "$mountpoint/sys/kernel/security/apparmor/features/"
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/seccomp/generic.actions_avail "$mountpoint/proc/sys/kernel/seccomp/actions_avail"
# cgroup2 mount for LP: 1944004
mount -t cgroup2 none "$mountpoint/sys/fs/cgroup"
mount -t tmpfs none "$mountpoint/tmp"
@ -408,7 +408,7 @@ create_squashfs() {
squashfs_file="$2"
config_dir="$PWD/config"
(cd $rootfs_dir &&
mksquashfs . $squashfs_file -no-progress -xattrs -comp xz \
mksquashfs . $squashfs_file -no-progress -xattrs -comp "${SQUASHFS_COMP:-xz}" \
-ef "$config_dir/squashfs-exclude-files")
}
@ -860,7 +860,7 @@ snap_validate_seed() {
fi
if [ ${boot_filename} != undefined ]; then # we have a known boot file so we can proceed with checking for features to mount
kern_major_min=$(readlink --canonicalize --no-newline ${CHROOT_ROOT}/boot/${boot_filename} | grep --extended-regexp --only-matching --max-count 1 '[0-9]+\.[0-9]+')
if [ -d /usr/share/livecd-rootfs/live-build/apparmor/${kern_major_min} ]; then
if [ -d ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/${kern_major_min} ]; then
# if an Ubuntu version has different kernel apparmor features between LTS and HWE kernels
# a snap pre-seeding issue can occur, where the incorrect apparmor features are reported
# basic copy of a directory structure overriding the "generic" feature set
@ -868,7 +868,7 @@ snap_validate_seed() {
# Bind kernel apparmor directory to feature directory for snap preseeding
umount "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
mount --bind /usr/share/livecd-rootfs/live-build/apparmor/${kern_major_min} "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
mount --bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/${kern_major_min} "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
fi
fi
@ -894,7 +894,7 @@ snap_validate_seed() {
# mount generic apparmor feature again (cleanup)
if [ -d /build/config/hooks.d/extra/apparmor/${kern_major_min} ]; then
umount "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
mount -o bind /usr/share/livecd-rootfs/live-build/apparmor/generic "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/generic "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
fi
}
@ -1254,7 +1254,7 @@ setup_cidata() {
local mountpoint=$(mktemp -d)
mkfs.vfat -F 32 -n CIDATA ${cidata_dev}
mount ${cidata_dev} ${mountpoint}
cp /usr/share/livecd-rootfs/live-build/cidata/* ${mountpoint}
cp ${LIVECD_ROOTFS_ROOT}/live-build/cidata/* ${mountpoint}
cat >>${mountpoint}/meta-data.sample <<END
#instance-id: iid-$(openssl rand -hex 8)
@ -1454,5 +1454,5 @@ gpt_root_partition_uuid() {
# is importable, and uses config/iso-dir as the standard working directory
# for ISO metadata and intermediate files.
isobuild () {
PYTHONPATH=/usr/share/livecd-rootfs/live-build/ /usr/share/livecd-rootfs/live-build/isobuild --workdir config/iso-dir "$@"
PYTHONPATH=${LIVECD_ROOTFS_ROOT}/live-build/ ${LIVECD_ROOTFS_ROOT}/live-build/isobuild --workdir config/iso-dir "$@"
}

View File

@ -42,6 +42,7 @@ project_to_capproject_map = {
"ubuntu-core-installer": "Ubuntu-Core-Installer",
"ubuntu-mate": "Ubuntu-MATE",
"ubuntu-mini-iso": "Ubuntu-Mini-ISO",
"ubuntu-test-iso": "Ubuntu-Test-ISO",
"ubuntu-oem": "Ubuntu OEM",
"ubuntu-server": "Ubuntu-Server",
"ubuntu-unity": "Ubuntu-Unity",

View File

@ -180,7 +180,7 @@ build_layered_squashfs () {
# Operate on the upperdir directly, so that we are only
# modifying mtime on files that are actually changed in
# this layer. LP: #2107332
/usr/share/livecd-rootfs/sync-mtime chroot "$overlay_dir"
${LIVECD_ROOTFS_ROOT}/sync-mtime chroot "$overlay_dir"
fi
create_squashfs "${overlay_dir}" ${squashfs_f}
@ -206,7 +206,7 @@ build_layered_squashfs () {
if [ -f config/seeded-languages ]; then
usc_opts="$usc_opts --langs $(cat config/seeded-languages)"
fi
/usr/share/livecd-rootfs/update-source-catalog source $usc_opts
${LIVECD_ROOTFS_ROOT}/update-source-catalog source $usc_opts
else
echo "No catalog entry template for $pass"
fi
@ -227,7 +227,7 @@ done
if [ -n "$DEFAULT_KERNEL" -a -f livecd.${PROJECT_FULL}.install-sources.yaml ]; then
write_kernel_yaml "$DEFAULT_KERNEL" "$BRIDGE_KERNEL_REASONS"
/usr/share/livecd-rootfs/update-source-catalog merge \
${LIVECD_ROOTFS_ROOT}/update-source-catalog merge \
--output livecd.${PROJECT_FULL}.install-sources.yaml \
--template config/kernel.yaml
fi

View File

@ -237,7 +237,7 @@ create_chroot_pass () {
lb chroot_interactive ${*}
# Misc ubuntu cleanup and post-layer configuration
/usr/share/livecd-rootfs/minimize-manual chroot
${LIVECD_ROOTFS_ROOT}/minimize-manual chroot
clean_debian_chroot
Chroot chroot "dpkg-query -W" > chroot.packages.${pass}

View File

@ -11,6 +11,7 @@ case ${PASS:-} in
esac
. config/binary
. config/common
. config/functions
case ${SUBPROJECT} in
@ -56,4 +57,4 @@ PROJECT_FULL=$PROJECT${SUBARCH:+-$SUBARCH}
usc_opts="--output livecd.${PROJECT_FULL}.install-sources.yaml \
--template config/edge.catalog-in.yaml \
--size 0"
/usr/share/livecd-rootfs/update-source-catalog source $usc_opts
${LIVECD_ROOTFS_ROOT}/update-source-catalog source $usc_opts

View File

@ -0,0 +1,8 @@
#!/bin/sh
set -eu
mkdir -p "etc/initramfs-tools/conf.d"
cat > etc/initramfs-tools/conf.d/casperize.conf <<EOF
export CASPER_GENERATE_UUID=1
EOF

View File

@ -0,0 +1,15 @@
#!/bin/sh
# Copy kernel/initrd artifacts for isobuilder to consume.
# The MAKE_ISO flow in auto/build expects ${PREFIX}.kernel-* and
# ${PREFIX}.initrd-* files. With --linux-packages=none live-build won't
# create them, so we do it here (mirroring ubuntu-mini-iso's approach).
# This hook runs for every pass; exit early when the kernel isn't present.
set -eu
[ -e chroot/boot/vmlinuz ] || exit 0
[ -e chroot/boot/initrd.img ] || exit 0
PREFIX="livecd.${PROJECT}"
cp chroot/boot/vmlinuz "${PREFIX}.kernel-generic"
cp chroot/boot/initrd.img "${PREFIX}.initrd-generic"

View File

@ -7,10 +7,12 @@
set -e
. config/common
chroot_directory=$1
auto_packages=$(/usr/share/livecd-rootfs/auto-markable-pkgs $chroot_directory)
auto_packages=$(${LIVECD_ROOTFS_ROOT}/auto-markable-pkgs $chroot_directory)
if [ -n "$auto_packages" ]; then
chroot $chroot_directory apt-mark auto $auto_packages
fi
[ -z "$(/usr/share/livecd-rootfs/auto-markable-pkgs $chroot_directory 2> /dev/null)" ]
[ -z "$(${LIVECD_ROOTFS_ROOT}/auto-markable-pkgs $chroot_directory 2> /dev/null)" ]