blob: da0169544e90bda3378b1992fc0697e428111e5b [file] [log] [blame]
Jiyong Parka128bad2024-09-20 16:53:57 +09001#!/bin/bash
2
3# This is a script to build a Debian image that can run in a VM created via AVF.
4# TODOs:
Jiyong Parka128bad2024-09-20 16:53:57 +09005# - Add Android-specific packages via a new class
6# - Use a stable release from debian-cloud-images
7
8show_help() {
maciek swiech0fdd0512024-10-11 15:12:44 +00009 echo "Usage: sudo $0 [OPTION]... [FILE]"
10 echo "Builds a debian image and save it to FILE. [sudo is required]"
11 echo "Options:"
12 echo "-h Print usage and this help message and exit."
Saswat Padhibf8a9cb2024-12-04 02:32:33 +000013 echo "-a ARCH Architecture of the image [default is host arch: $(uname -m)]"
Saswat Padhiac62a8b2024-12-06 00:48:07 +000014 echo "-k Build and use our custom kernel [default is cloud kernel]"
Jeongik Cha06f4ac52024-11-12 15:56:05 +090015 echo "-r Release mode build"
Saswat Padhibf8a9cb2024-12-04 02:32:33 +000016 echo "-w Save temp work directory [for debugging]"
Jiyong Parka128bad2024-09-20 16:53:57 +090017}
18
19check_sudo() {
20 if [ "$EUID" -ne 0 ]; then
Saswat Padhibf8a9cb2024-12-04 02:32:33 +000021 echo "Please run as root." ; exit 1
Jiyong Parka128bad2024-09-20 16:53:57 +090022 fi
23}
24
25parse_options() {
Saswat Padhiac62a8b2024-12-06 00:48:07 +000026 while getopts "a:hkrw" option; do
Jiyong Parka128bad2024-09-20 16:53:57 +090027 case ${option} in
28 h)
Saswat Padhibf8a9cb2024-12-04 02:32:33 +000029 show_help ; exit
30 ;;
maciek swiech0fdd0512024-10-11 15:12:44 +000031 a)
maciek swiech0fdd0512024-10-11 15:12:44 +000032 arch="$OPTARG"
maciek swiech0fdd0512024-10-11 15:12:44 +000033 ;;
Saswat Padhiac62a8b2024-12-06 00:48:07 +000034 k)
35 use_custom_kernel=1
36 ;;
Jeongik Cha06f4ac52024-11-12 15:56:05 +090037 r)
38 mode=release
39 ;;
Saswat Padhi26c4ef32024-11-29 19:46:53 +000040 w)
41 save_workdir=1
42 ;;
maciek swiech0fdd0512024-10-11 15:12:44 +000043 *)
Saswat Padhibf8a9cb2024-12-04 02:32:33 +000044 echo "Invalid option: $OPTARG" ; exit 1
maciek swiech0fdd0512024-10-11 15:12:44 +000045 ;;
Jiyong Parka128bad2024-09-20 16:53:57 +090046 esac
47 done
Saswat Padhibf8a9cb2024-12-04 02:32:33 +000048 case "$arch" in
49 aarch64)
50 debian_arch="arm64"
51 ;;
52 x86_64)
53 debian_arch="amd64"
54 ;;
55 *)
56 echo "Invalid architecture: $arch" ; exit 1
57 ;;
58 esac
maciek swiech0fdd0512024-10-11 15:12:44 +000059 if [[ "${*:$OPTIND:1}" ]]; then
Jiyong Park0b3a2ba2024-12-23 12:54:21 +090060 output="${*:$OPTIND:1}"
Jiyong Parka128bad2024-09-20 16:53:57 +090061 fi
62}
63
Jiyong Park879ee4a2024-11-29 14:00:47 +090064prepare_build_id() {
Jiyong Park879ee4a2024-11-29 14:00:47 +090065 if [ -z "${KOKORO_BUILD_NUMBER}" ]; then
Jiyong Parkec71e582024-12-23 14:21:57 +090066 echo eng-$(hostname)-$(date --utc)
Jiyong Park879ee4a2024-11-29 14:00:47 +090067 else
Jiyong Parkec71e582024-12-23 14:21:57 +090068 echo ${KOKORO_BUILD_NUMBER}
Jiyong Park879ee4a2024-11-29 14:00:47 +090069 fi
Jiyong Park879ee4a2024-11-29 14:00:47 +090070}
71
Jiyong Parka128bad2024-09-20 16:53:57 +090072install_prerequisites() {
Jiyong Park0e565ed2024-09-24 12:39:53 +090073 apt update
maciek swiech0fdd0512024-10-11 15:12:44 +000074 packages=(
Jeongik Cha1542d152024-12-04 13:22:09 +090075 apt-utils
Jeongik Cha7e7f19d2024-10-31 20:50:24 +090076 automake
maciek swiech0fdd0512024-10-11 15:12:44 +000077 binfmt-support
78 build-essential
79 ca-certificates
Jeongik Cha7e7f19d2024-10-31 20:50:24 +090080 cmake
maciek swiech0fdd0512024-10-11 15:12:44 +000081 curl
82 debsums
83 dosfstools
84 fai-server
85 fai-setup-storage
86 fdisk
Jeongik Cha7e7f19d2024-10-31 20:50:24 +090087 git
88 libjson-c-dev
89 libtool
90 libwebsockets-dev
maciek swiech0fdd0512024-10-11 15:12:44 +000091 make
Jeongik Chace3a3962024-10-12 03:47:23 +090092 protobuf-compiler
maciek swiech0fdd0512024-10-11 15:12:44 +000093 python3
94 python3-libcloud
95 python3-marshmallow
96 python3-pytest
97 python3-yaml
98 qemu-user-static
99 qemu-utils
100 sudo
101 udev
102 )
103 if [[ "$arch" == "aarch64" ]]; then
104 packages+=(
105 gcc-aarch64-linux-gnu
106 libc6-dev-arm64-cross
107 qemu-system-arm
108 )
109 else
110 packages+=(
Jeongik Cha904d9622024-10-21 11:16:37 +0900111 qemu-system
Jeongik Cha8e711982024-10-20 12:45:35 +0900112 )
113 fi
114
115 # TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
116 if [[ "$arch" == "x86_64" ]]; then
117 packages+=(
118 libguestfs-tools
Saswat Padhi79f52132024-11-27 03:56:40 +0000119 linux-image-generic
maciek swiech0fdd0512024-10-11 15:12:44 +0000120 )
121 fi
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000122
123 if [[ "$use_custom_kernel" -eq 1 ]]; then
124 packages+=(
125 bc
126 bison
127 debhelper
128 dh-exec
129 flex
130 gcc-12
131 kernel-wedge
132 libelf-dev
133 libpci-dev
134 lz4
135 pahole
136 python3-jinja2
137 python3-docutils
138 quilt
139 rsync
140 )
141 if [[ "$arch" == "aarch64" ]]; then
142 packages+=(
143 gcc-arm-linux-gnueabihf
144 gcc-12-aarch64-linux-gnu
145 )
146 fi
147 fi
148
Jiyong Park44dd28f2024-09-20 18:47:40 +0900149 DEBIAN_FRONTEND=noninteractive \
maciek swiech0fdd0512024-10-11 15:12:44 +0000150 apt install --no-install-recommends --assume-yes "${packages[@]}"
Jeongik Chab137a5f2024-10-02 12:53:05 +0900151
maciek swiech0fdd0512024-10-11 15:12:44 +0000152 if [ ! -f $"HOME"/.cargo/bin/cargo ]; then
Seungjae Yoo198a0fb2024-10-04 16:29:12 +0900153 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
154 fi
155
maciek swiech0fdd0512024-10-11 15:12:44 +0000156 source "$HOME"/.cargo/env
157 rustup target add "${arch}"-unknown-linux-gnu
Jeongik Cha139ddfd2024-11-01 23:16:44 +0900158 cargo install cargo-license
Jiyong Parkff0dc0d2025-01-06 17:38:21 +0900159 cargo install cargo-deb
Jiyong Parka128bad2024-09-20 16:53:57 +0900160}
161
162download_debian_cloud_image() {
163 local ver=master
164 local prj=debian-cloud-images
maciek swiech0fdd0512024-10-11 15:12:44 +0000165 local url="https://salsa.debian.org/cloud-team/${prj}/-/archive/${ver}/${prj}-${ver}.tar.gz"
166 local outdir="${debian_cloud_image}"
Jiyong Parka128bad2024-09-20 16:53:57 +0900167
maciek swiech0fdd0512024-10-11 15:12:44 +0000168 mkdir -p "${outdir}"
169 wget -O - "${url}" | tar xz -C "${outdir}" --strip-components=1
Jiyong Parka128bad2024-09-20 16:53:57 +0900170}
171
Jiyong Parkff0dc0d2025-01-06 17:38:21 +0900172build_rust_as_deb() {
Seungjae Yoo1cfcb582024-10-17 14:06:58 +0900173 pushd "$(dirname "$0")/../../guest/$1" > /dev/null
Jiyong Parkff0dc0d2025-01-06 17:38:21 +0900174 cargo deb \
Seungjae Yoo1cfcb582024-10-17 14:06:58 +0900175 --target "${arch}-unknown-linux-gnu" \
Jiyong Parkff0dc0d2025-01-06 17:38:21 +0900176 --output "${debian_cloud_image}/localdebs"
Seungjae Yoo1cfcb582024-10-17 14:06:58 +0900177 popd > /dev/null
178}
179
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900180build_ttyd() {
181 local ttyd_version=1.7.7
182 local url="https://github.com/tsl0922/ttyd/archive/refs/tags/${ttyd_version}.tar.gz"
maciek swieche17e59f2024-11-25 20:13:23 +0000183 cp -r "$(dirname "$0")/ttyd" "${workdir}/ttyd"
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900184
185 pushd "${workdir}" > /dev/null
186 wget "${url}" -O - | tar xz
187 cp ttyd/* ttyd-${ttyd_version}/scripts
188 pushd "$workdir/ttyd-${ttyd_version}" > /dev/null
189 bash -c "env BUILD_TARGET=${arch} ./scripts/cross-build.sh"
190 mkdir -p "${dst}/files/usr/local/bin/ttyd"
maciek swieche17e59f2024-11-25 20:13:23 +0000191 cp "/tmp/stage/${arch}-linux-musl/bin/ttyd" "${dst}/files/usr/local/bin/ttyd/AVF"
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900192 chmod 777 "${dst}/files/usr/local/bin/ttyd/AVF"
Jeongik Cha139ddfd2024-11-01 23:16:44 +0900193 mkdir -p "${dst}/files/usr/share/doc/ttyd"
194 cp LICENSE "${dst}/files/usr/share/doc/ttyd/copyright"
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900195 popd > /dev/null
196 popd > /dev/null
197}
198
Jiyong Park44dd28f2024-09-20 18:47:40 +0900199copy_android_config() {
maciek swieche17e59f2024-11-25 20:13:23 +0000200 local src
201 local dst
202 src="$(dirname "$0")/fai_config"
203 dst="${config_space}"
Jiyong Park44dd28f2024-09-20 18:47:40 +0900204
maciek swiech0fdd0512024-10-11 15:12:44 +0000205 cp -R "${src}"/* "${dst}"
206 cp "$(dirname "$0")/image.yaml" "${resources_dir}"
Jeongik Cha50952062024-09-23 18:13:38 +0900207
Jeongik Cha1542d152024-12-04 13:22:09 +0900208 cp -R "$(dirname "$0")/localdebs/" "${debian_cloud_image}/"
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900209 build_ttyd
Jiyong Parkff0dc0d2025-01-06 17:38:21 +0900210 build_rust_as_deb forwarder_guest
211 build_rust_as_deb forwarder_guest_launcher
212 build_rust_as_deb shutdown_runner
Jiyong Park44dd28f2024-09-20 18:47:40 +0900213}
214
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000215package_custom_kernel() {
216 if [[ "$use_custom_kernel" != 1 ]]; then
217 echo "linux-headers-generic" >> "${config_space}/package_config/AVF"
218 return
219 fi
220
Saswat Padhif28d2172025-01-16 14:28:10 -0800221 local deb_base_url="https://deb.debian.org/debian"
222 local deb_security_base_url="https://security.debian.org/debian-security"
223
224 local pool_dir="pool/main/l/linux"
225 local ksrc_base_url="${deb_base_url}/${pool_dir}"
226 local ksrc_security_base_url="${deb_security_base_url}/${pool_dir}"
227
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000228 # NOTE: 6.1 is the latest LTS kernel for which Debian's kernel build scripts
229 # work on Python 3.10, the default version on our Ubuntu 22.04 builders.
Saswat Padhi6c1aaf32025-01-22 12:47:20 -0800230 #
231 # We track the latest Debian stable kernel version for the 6.1 branch,
232 # which can be found at:
233 # https://packages.debian.org/stable/linux-source-6.1
234 local debian_kver="6.1.123-1"
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000235
Saswat Padhif28d2172025-01-16 14:28:10 -0800236 local dsc_file="linux_${debian_kver}.dsc"
237 local orig_ksrc_file="linux_${debian_kver%-*}.orig.tar.xz"
238 local debian_ksrc_file="linux_${debian_kver}.debian.tar.xz"
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000239
Saswat Padhi74b3ac92024-12-11 13:41:59 -0800240 # 0. Grab the kernel sources, and the latest debian keyrings
241 mkdir -p "${workdir}/kernel"
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000242 pushd "${workdir}/kernel" > /dev/null
Saswat Padhif28d2172025-01-16 14:28:10 -0800243
244 wget "${ksrc_security_base_url}/${dsc_file}" || \
245 wget "${ksrc_base_url}/${dsc_file}"
246
247 wget "${ksrc_security_base_url}/${orig_ksrc_file}" || \
248 wget "${ksrc_base_url}/${orig_ksrc_file}"
249
250 wget "${ksrc_security_base_url}/${debian_ksrc_file}" || \
251 wget "${ksrc_base_url}/${debian_ksrc_file}"
252
Saswat Padhi74b3ac92024-12-11 13:41:59 -0800253 rsync -az --progress keyring.debian.org::keyrings/keyrings/ /usr/share/keyrings/
254
255 # 1. Verify, extract and merge patches into the original kernel sources
256 dpkg-source --require-strong-checksums \
257 --require-valid-signature \
Saswat Padhif28d2172025-01-16 14:28:10 -0800258 --extract "${dsc_file}"
Saswat Padhi74b3ac92024-12-11 13:41:59 -0800259 pushd "linux-${debian_kver%-*}" > /dev/null
Saswat Padhi61fbaed2025-01-16 15:58:00 -0800260
261 local kpatches_src="$(dirname "$0")/kernel_patches"
262 cp -r "${kpatches_src}/avf" debian/patches/
263 cat "${kpatches_src}/series" >> debian/patches/series
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000264 ./debian/rules orig
265
Saswat Padhif28d2172025-01-16 14:28:10 -0800266 local custom_flavour="avf"
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000267 local debarch_flavour="${custom_flavour}-${debian_arch}"
Saswat Padhif28d2172025-01-16 14:28:10 -0800268
269 local abi_kver="$(sed -nE 's;Package: linux-support-(.*);\1;p' debian/control)"
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000270 local abi_flavour="${abi_kver}-${debarch_flavour}"
271
272 # 2. Define our custom flavour and regenerate control file
273 # NOTE: Our flavour extends Debian's `cloud` config on the `none` featureset.
274 cat > debian/config/${debian_arch}/config.${debarch_flavour} <<EOF
275# TODO: Add our custom kernel config to this file
276EOF
277
278 sed -z "s;\[base\]\nflavours:;[base]\nflavours:\n ${debarch_flavour};" \
279 -i debian/config/${debian_arch}/none/defines
280 cat >> debian/config/${debian_arch}/none/defines <<EOF
281[${debarch_flavour}_image]
282configs:
283 config.cloud
284 ${debian_arch}/config.${debarch_flavour}
285EOF
286 cat >> debian/config/${debian_arch}/defines <<EOF
287[${debarch_flavour}_description]
288hardware: ${arch} AVF
289hardware-long: ${arch} Android Virtualization Framework
290EOF
291 ./debian/rules debian/control || true
292
293 # 3. Build the kernel and generate Debian packages
294 ./debian/rules source
295 [[ "$arch" == "$(uname -m)" ]] || export $(dpkg-architecture -a $debian_arch)
296 make -j$(nproc) -f debian/rules.gen \
297 "binary-arch_${debian_arch}_none_${debarch_flavour}"
298
299 # 4. Copy the packages to localdebs and add their names to package_config/AVF
300 popd > /dev/null
301 cp "linux-headers-${abi_flavour}_${debian_kver}_${debian_arch}.deb" \
302 "linux-image-${abi_flavour}-unsigned_${debian_kver}_${debian_arch}.deb" \
303 "${debian_cloud_image}/localdebs/"
304 popd > /dev/null
305 cat >> "${config_space}/package_config/AVF" <<EOF
306linux-headers-${abi_flavour}
307linux-image-${abi_flavour}-unsigned
308EOF
309}
310
Jiyong Parka128bad2024-09-20 16:53:57 +0900311run_fai() {
Jiyong Park0b3a2ba2024-12-23 12:54:21 +0900312 local out="${raw_disk_image}"
maciek swiech0fdd0512024-10-11 15:12:44 +0000313 make -C "${debian_cloud_image}" "image_bookworm_nocloud_${debian_arch}"
314 mv "${debian_cloud_image}/image_bookworm_nocloud_${debian_arch}.raw" "${out}"
Jiyong Parka128bad2024-09-20 16:53:57 +0900315}
316
Jiyong Parkdfec0202024-12-23 13:24:01 +0900317generate_output_package() {
318 fdisk -l "${raw_disk_image}"
Jiyong Park159b8f42024-12-26 18:05:22 +0900319 local vm_config="$(realpath $(dirname "$0"))/vm_config.json.${arch}"
320 local root_partition_num=1
321 local bios_partition_num=14
322 local efi_partition_num=15
Mu-Le Lee955b6582024-11-01 15:40:58 +0800323
Jiyong Parkec71e582024-12-23 14:21:57 +0900324 pushd ${workdir} > /dev/null
325
326 echo ${build_id} > build_id
327
Jiyong Park0b3a2ba2024-12-23 12:54:21 +0900328 loop=$(losetup -f --show --partscan $raw_disk_image)
maciek swieche17e59f2024-11-25 20:13:23 +0000329 dd if="${loop}p$root_partition_num" of=root_part
330 if [[ "$arch" == "x86_64" ]]; then
331 dd if="${loop}p$bios_partition_num" of=bios_part
332 fi
333 dd if="${loop}p$efi_partition_num" of=efi_part
334 losetup -d "${loop}"
Mu-Le Lee955b6582024-11-01 15:40:58 +0800335
Jiyong Parkec71e582024-12-23 14:21:57 +0900336 cp ${vm_config} vm_config.json
Jiyong Park0b3a2ba2024-12-23 12:54:21 +0900337 sed -i "s/{root_part_guid}/$(sfdisk --part-uuid $raw_disk_image $root_partition_num)/g" vm_config.json
maciek swieche17e59f2024-11-25 20:13:23 +0000338 if [[ "$arch" == "x86_64" ]]; then
Jiyong Park0b3a2ba2024-12-23 12:54:21 +0900339 sed -i "s/{bios_part_guid}/$(sfdisk --part-uuid $raw_disk_image $bios_partition_num)/g" vm_config.json
maciek swieche17e59f2024-11-25 20:13:23 +0000340 fi
Jiyong Park0b3a2ba2024-12-23 12:54:21 +0900341 sed -i "s/{efi_part_guid}/$(sfdisk --part-uuid $raw_disk_image $efi_partition_num)/g" vm_config.json
Jiyong Parkdfec0202024-12-23 13:24:01 +0900342
343 images=()
344 if [[ "$arch" == "aarch64" ]]; then
345 images+=(
346 root_part
347 efi_part
348 )
349 # TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
350 elif [[ "$arch" == "x86_64" ]]; then
351 rm -f vmlinuz initrd.img
352 virt-get-kernel -a "${raw_disk_image}"
353 mv vmlinuz* vmlinuz
354 mv initrd.img* initrd.img
355 images+=(
356 bios_part
357 root_part
358 efi_part
359 vmlinuz
360 initrd.img
361 )
362 fi
363
Jiyong Parkec71e582024-12-23 14:21:57 +0900364 popd > /dev/null
365
Jiyong Parkdfec0202024-12-23 13:24:01 +0900366 # --sparse option isn't supported in apache-commons-compress
Jiyong Parkec71e582024-12-23 14:21:57 +0900367 tar czv -f ${output} -C ${workdir} build_id "${images[@]}" vm_config.json
Mu-Le Lee955b6582024-11-01 15:40:58 +0800368}
369
Jiyong Parka128bad2024-09-20 16:53:57 +0900370clean_up() {
Saswat Padhibf8a9cb2024-12-04 02:32:33 +0000371 [ "$save_workdir" -eq 1 ] || rm -rf "${workdir}"
Jiyong Parka128bad2024-09-20 16:53:57 +0900372}
373
374set -e
375trap clean_up EXIT
376
Jiyong Park0b3a2ba2024-12-23 12:54:21 +0900377output=images.tar.gz
Jiyong Parka128bad2024-09-20 16:53:57 +0900378workdir=$(mktemp -d)
Jiyong Parkec71e582024-12-23 14:21:57 +0900379raw_disk_image=${workdir}/image.raw
Jiyong Park879ee4a2024-11-29 14:00:47 +0900380build_id=$(prepare_build_id)
Jiyong Parka128bad2024-09-20 16:53:57 +0900381debian_cloud_image=${workdir}/debian_cloud_image
Jiyong Park44dd28f2024-09-20 18:47:40 +0900382debian_version=bookworm
383config_space=${debian_cloud_image}/config_space/${debian_version}
Jeongik Cha37047c32024-09-20 23:09:16 +0900384resources_dir=${debian_cloud_image}/src/debian_cloud_images/resources
Saswat Padhibf8a9cb2024-12-04 02:32:33 +0000385arch="$(uname -m)"
Jeongik Cha06f4ac52024-11-12 15:56:05 +0900386mode=debug
Saswat Padhi26c4ef32024-11-29 19:46:53 +0000387save_workdir=0
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000388use_custom_kernel=0
Jiyong Park879ee4a2024-11-29 14:00:47 +0900389
maciek swiech0fdd0512024-10-11 15:12:44 +0000390parse_options "$@"
Jiyong Parka128bad2024-09-20 16:53:57 +0900391check_sudo
Jiyong Parka128bad2024-09-20 16:53:57 +0900392install_prerequisites
393download_debian_cloud_image
Jiyong Park44dd28f2024-09-20 18:47:40 +0900394copy_android_config
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000395package_custom_kernel
Jiyong Park0e565ed2024-09-24 12:39:53 +0900396run_fai
Jiyong Parkdfec0202024-12-23 13:24:01 +0900397generate_output_package