blob: 3db6a40ec00baf2b304bbd650201c0f46361e87e [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
60 built_image="${*:$OPTIND:1}"
Jiyong Parka128bad2024-09-20 16:53:57 +090061 fi
62}
63
Jiyong Park879ee4a2024-11-29 14:00:47 +090064prepare_build_id() {
Jeongik Chae0fd9e62024-12-02 14:28:50 +090065 local filename=build_id
Jiyong Park879ee4a2024-11-29 14:00:47 +090066 if [ -z "${KOKORO_BUILD_NUMBER}" ]; then
Jeongik Chabf0373b2024-12-02 15:18:47 +090067 echo eng-$(hostname)-$(date --utc) > ${filename}
Jiyong Park879ee4a2024-11-29 14:00:47 +090068 else
Jeongik Chabf0373b2024-12-02 15:18:47 +090069 echo ${KOKORO_BUILD_NUMBER} > ${filename}
Jiyong Park879ee4a2024-11-29 14:00:47 +090070 fi
Jeongik Chae0fd9e62024-12-02 14:28:50 +090071 echo ${filename}
Jiyong Park879ee4a2024-11-29 14:00:47 +090072}
73
Jiyong Parka128bad2024-09-20 16:53:57 +090074install_prerequisites() {
Jiyong Park0e565ed2024-09-24 12:39:53 +090075 apt update
maciek swiech0fdd0512024-10-11 15:12:44 +000076 packages=(
Jeongik Cha1542d152024-12-04 13:22:09 +090077 apt-utils
Jeongik Cha7e7f19d2024-10-31 20:50:24 +090078 automake
maciek swiech0fdd0512024-10-11 15:12:44 +000079 binfmt-support
80 build-essential
81 ca-certificates
Jeongik Cha7e7f19d2024-10-31 20:50:24 +090082 cmake
maciek swiech0fdd0512024-10-11 15:12:44 +000083 curl
84 debsums
85 dosfstools
86 fai-server
87 fai-setup-storage
88 fdisk
Jeongik Cha7e7f19d2024-10-31 20:50:24 +090089 git
90 libjson-c-dev
91 libtool
92 libwebsockets-dev
maciek swiech0fdd0512024-10-11 15:12:44 +000093 make
Jeongik Chace3a3962024-10-12 03:47:23 +090094 protobuf-compiler
maciek swiech0fdd0512024-10-11 15:12:44 +000095 python3
96 python3-libcloud
97 python3-marshmallow
98 python3-pytest
99 python3-yaml
100 qemu-user-static
101 qemu-utils
102 sudo
103 udev
104 )
105 if [[ "$arch" == "aarch64" ]]; then
106 packages+=(
107 gcc-aarch64-linux-gnu
108 libc6-dev-arm64-cross
109 qemu-system-arm
110 )
111 else
112 packages+=(
Jeongik Cha904d9622024-10-21 11:16:37 +0900113 qemu-system
Jeongik Cha8e711982024-10-20 12:45:35 +0900114 )
115 fi
116
117 # TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
118 if [[ "$arch" == "x86_64" ]]; then
119 packages+=(
120 libguestfs-tools
Saswat Padhi79f52132024-11-27 03:56:40 +0000121 linux-image-generic
maciek swiech0fdd0512024-10-11 15:12:44 +0000122 )
123 fi
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000124
125 if [[ "$use_custom_kernel" -eq 1 ]]; then
126 packages+=(
127 bc
128 bison
129 debhelper
130 dh-exec
131 flex
132 gcc-12
133 kernel-wedge
134 libelf-dev
135 libpci-dev
136 lz4
137 pahole
138 python3-jinja2
139 python3-docutils
140 quilt
141 rsync
142 )
143 if [[ "$arch" == "aarch64" ]]; then
144 packages+=(
145 gcc-arm-linux-gnueabihf
146 gcc-12-aarch64-linux-gnu
147 )
148 fi
149 fi
150
Jiyong Park44dd28f2024-09-20 18:47:40 +0900151 DEBIAN_FRONTEND=noninteractive \
maciek swiech0fdd0512024-10-11 15:12:44 +0000152 apt install --no-install-recommends --assume-yes "${packages[@]}"
Jeongik Chab137a5f2024-10-02 12:53:05 +0900153
maciek swiech0fdd0512024-10-11 15:12:44 +0000154 if [ ! -f $"HOME"/.cargo/bin/cargo ]; then
Seungjae Yoo198a0fb2024-10-04 16:29:12 +0900155 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
156 fi
157
maciek swiech0fdd0512024-10-11 15:12:44 +0000158 source "$HOME"/.cargo/env
159 rustup target add "${arch}"-unknown-linux-gnu
Jeongik Cha139ddfd2024-11-01 23:16:44 +0900160 cargo install cargo-license
Jiyong Parka128bad2024-09-20 16:53:57 +0900161}
162
163download_debian_cloud_image() {
164 local ver=master
165 local prj=debian-cloud-images
maciek swiech0fdd0512024-10-11 15:12:44 +0000166 local url="https://salsa.debian.org/cloud-team/${prj}/-/archive/${ver}/${prj}-${ver}.tar.gz"
167 local outdir="${debian_cloud_image}"
Jiyong Parka128bad2024-09-20 16:53:57 +0900168
maciek swiech0fdd0512024-10-11 15:12:44 +0000169 mkdir -p "${outdir}"
170 wget -O - "${url}" | tar xz -C "${outdir}" --strip-components=1
Jiyong Parka128bad2024-09-20 16:53:57 +0900171}
172
Seungjae Yoo1cfcb582024-10-17 14:06:58 +0900173build_rust_binary_and_copy() {
174 pushd "$(dirname "$0")/../../guest/$1" > /dev/null
Jeongik Cha06f4ac52024-11-12 15:56:05 +0900175 local release_flag=
176 local artifact_mode=debug
177 if [[ "$mode" == "release" ]]; then
178 release_flag="--release"
179 artifact_mode=release
180 fi
Seungjae Yoo1cfcb582024-10-17 14:06:58 +0900181 RUSTFLAGS="-C linker=${arch}-linux-gnu-gcc" cargo build \
182 --target "${arch}-unknown-linux-gnu" \
Jeongik Cha06f4ac52024-11-12 15:56:05 +0900183 --target-dir "${workdir}/$1" ${release_flag}
Seungjae Yoo1cfcb582024-10-17 14:06:58 +0900184 mkdir -p "${dst}/files/usr/local/bin/$1"
Jeongik Cha5d399fb2024-11-12 19:44:33 +0900185 cp "${workdir}/$1/${arch}-unknown-linux-gnu/${artifact_mode}/$1" "${dst}/files/usr/local/bin/$1/AVF"
Seungjae Yoo1cfcb582024-10-17 14:06:58 +0900186 chmod 777 "${dst}/files/usr/local/bin/$1/AVF"
Jeongik Cha139ddfd2024-11-01 23:16:44 +0900187
188 mkdir -p "${dst}/files/usr/share/doc/$1"
189 cargo license > "${dst}/files/usr/share/doc/$1/copyright"
Seungjae Yoo1cfcb582024-10-17 14:06:58 +0900190 popd > /dev/null
191}
192
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900193build_ttyd() {
194 local ttyd_version=1.7.7
195 local url="https://github.com/tsl0922/ttyd/archive/refs/tags/${ttyd_version}.tar.gz"
maciek swieche17e59f2024-11-25 20:13:23 +0000196 cp -r "$(dirname "$0")/ttyd" "${workdir}/ttyd"
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900197
198 pushd "${workdir}" > /dev/null
199 wget "${url}" -O - | tar xz
200 cp ttyd/* ttyd-${ttyd_version}/scripts
201 pushd "$workdir/ttyd-${ttyd_version}" > /dev/null
202 bash -c "env BUILD_TARGET=${arch} ./scripts/cross-build.sh"
203 mkdir -p "${dst}/files/usr/local/bin/ttyd"
maciek swieche17e59f2024-11-25 20:13:23 +0000204 cp "/tmp/stage/${arch}-linux-musl/bin/ttyd" "${dst}/files/usr/local/bin/ttyd/AVF"
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900205 chmod 777 "${dst}/files/usr/local/bin/ttyd/AVF"
Jeongik Cha139ddfd2024-11-01 23:16:44 +0900206 mkdir -p "${dst}/files/usr/share/doc/ttyd"
207 cp LICENSE "${dst}/files/usr/share/doc/ttyd/copyright"
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900208 popd > /dev/null
209 popd > /dev/null
210}
211
Jiyong Park44dd28f2024-09-20 18:47:40 +0900212copy_android_config() {
maciek swieche17e59f2024-11-25 20:13:23 +0000213 local src
214 local dst
215 src="$(dirname "$0")/fai_config"
216 dst="${config_space}"
Jiyong Park44dd28f2024-09-20 18:47:40 +0900217
maciek swiech0fdd0512024-10-11 15:12:44 +0000218 cp -R "${src}"/* "${dst}"
219 cp "$(dirname "$0")/image.yaml" "${resources_dir}"
Jeongik Cha50952062024-09-23 18:13:38 +0900220
Jeongik Cha1542d152024-12-04 13:22:09 +0900221 cp -R "$(dirname "$0")/localdebs/" "${debian_cloud_image}/"
Jeongik Cha7e7f19d2024-10-31 20:50:24 +0900222 build_ttyd
Seungjae Yoo1cfcb582024-10-17 14:06:58 +0900223 build_rust_binary_and_copy forwarder_guest
224 build_rust_binary_and_copy forwarder_guest_launcher
Jeongik Cha3cea4812024-12-05 23:04:30 +0900225 build_rust_binary_and_copy shutdown_runner
Jiyong Park44dd28f2024-09-20 18:47:40 +0900226}
227
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000228package_custom_kernel() {
229 if [[ "$use_custom_kernel" != 1 ]]; then
230 echo "linux-headers-generic" >> "${config_space}/package_config/AVF"
231 return
232 fi
233
234 # NOTE: 6.1 is the latest LTS kernel for which Debian's kernel build scripts
235 # work on Python 3.10, the default version on our Ubuntu 22.04 builders.
236 local debian_kver="6.1.119-1"
237 local custom_flavour="avf"
238 local ksrc_base_url="https://deb.debian.org/debian/pool/main/l/linux"
239
Saswat Padhi74b3ac92024-12-11 13:41:59 -0800240 local dsc_url="${ksrc_base_url}/linux_${debian_kver}.dsc"
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000241 local debian_ksrc_url="${ksrc_base_url}/linux_${debian_kver}.debian.tar.xz"
242 local orig_ksrc_url="${ksrc_base_url}/linux_${debian_kver%-*}.orig.tar.xz"
243
Saswat Padhi74b3ac92024-12-11 13:41:59 -0800244 # 0. Grab the kernel sources, and the latest debian keyrings
245 mkdir -p "${workdir}/kernel"
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000246 pushd "${workdir}/kernel" > /dev/null
Saswat Padhi74b3ac92024-12-11 13:41:59 -0800247 wget "$dsc_url"
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000248 wget "$orig_ksrc_url"
Saswat Padhi74b3ac92024-12-11 13:41:59 -0800249 wget "$debian_ksrc_url"
250 rsync -az --progress keyring.debian.org::keyrings/keyrings/ /usr/share/keyrings/
251
252 # 1. Verify, extract and merge patches into the original kernel sources
253 dpkg-source --require-strong-checksums \
254 --require-valid-signature \
255 --extract linux_${debian_kver}.dsc
256 pushd "linux-${debian_kver%-*}" > /dev/null
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000257 # TODO: Copy our own kernel patches to debian/patches
258 # and add patch file names in the desired order to debian/patches/series
259 ./debian/rules orig
260
261 local abi_kver="$(sed -nE 's;Package: linux-support-(.*);\1;p' debian/control)"
262 local debarch_flavour="${custom_flavour}-${debian_arch}"
263 local abi_flavour="${abi_kver}-${debarch_flavour}"
264
265 # 2. Define our custom flavour and regenerate control file
266 # NOTE: Our flavour extends Debian's `cloud` config on the `none` featureset.
267 cat > debian/config/${debian_arch}/config.${debarch_flavour} <<EOF
268# TODO: Add our custom kernel config to this file
269EOF
270
271 sed -z "s;\[base\]\nflavours:;[base]\nflavours:\n ${debarch_flavour};" \
272 -i debian/config/${debian_arch}/none/defines
273 cat >> debian/config/${debian_arch}/none/defines <<EOF
274[${debarch_flavour}_image]
275configs:
276 config.cloud
277 ${debian_arch}/config.${debarch_flavour}
278EOF
279 cat >> debian/config/${debian_arch}/defines <<EOF
280[${debarch_flavour}_description]
281hardware: ${arch} AVF
282hardware-long: ${arch} Android Virtualization Framework
283EOF
284 ./debian/rules debian/control || true
285
286 # 3. Build the kernel and generate Debian packages
287 ./debian/rules source
288 [[ "$arch" == "$(uname -m)" ]] || export $(dpkg-architecture -a $debian_arch)
289 make -j$(nproc) -f debian/rules.gen \
290 "binary-arch_${debian_arch}_none_${debarch_flavour}"
291
292 # 4. Copy the packages to localdebs and add their names to package_config/AVF
293 popd > /dev/null
294 cp "linux-headers-${abi_flavour}_${debian_kver}_${debian_arch}.deb" \
295 "linux-image-${abi_flavour}-unsigned_${debian_kver}_${debian_arch}.deb" \
296 "${debian_cloud_image}/localdebs/"
297 popd > /dev/null
298 cat >> "${config_space}/package_config/AVF" <<EOF
299linux-headers-${abi_flavour}
300linux-image-${abi_flavour}-unsigned
301EOF
302}
303
Jiyong Parka128bad2024-09-20 16:53:57 +0900304run_fai() {
maciek swiech0fdd0512024-10-11 15:12:44 +0000305 local out="${built_image}"
306 make -C "${debian_cloud_image}" "image_bookworm_nocloud_${debian_arch}"
307 mv "${debian_cloud_image}/image_bookworm_nocloud_${debian_arch}.raw" "${out}"
Jiyong Parka128bad2024-09-20 16:53:57 +0900308}
309
Mu-Le Lee955b6582024-11-01 15:40:58 +0800310extract_partitions() {
311 root_partition_num=1
maciek swieche17e59f2024-11-25 20:13:23 +0000312 bios_partition_num=14
Mu-Le Lee955b6582024-11-01 15:40:58 +0800313 efi_partition_num=15
314
maciek swiech3919b8c2024-11-19 20:58:32 +0000315 loop=$(losetup -f --show --partscan $built_image)
maciek swieche17e59f2024-11-25 20:13:23 +0000316 dd if="${loop}p$root_partition_num" of=root_part
317 if [[ "$arch" == "x86_64" ]]; then
318 dd if="${loop}p$bios_partition_num" of=bios_part
319 fi
320 dd if="${loop}p$efi_partition_num" of=efi_part
321 losetup -d "${loop}"
Mu-Le Lee955b6582024-11-01 15:40:58 +0800322
maciek swiech3919b8c2024-11-19 20:58:32 +0000323 sed -i "s/{root_part_guid}/$(sfdisk --part-uuid $built_image $root_partition_num)/g" vm_config.json
maciek swieche17e59f2024-11-25 20:13:23 +0000324 if [[ "$arch" == "x86_64" ]]; then
325 sed -i "s/{bios_part_guid}/$(sfdisk --part-uuid $built_image $bios_partition_num)/g" vm_config.json
326 fi
maciek swiech3919b8c2024-11-19 20:58:32 +0000327 sed -i "s/{efi_part_guid}/$(sfdisk --part-uuid $built_image $efi_partition_num)/g" vm_config.json
Mu-Le Lee955b6582024-11-01 15:40:58 +0800328}
329
Jiyong Parka128bad2024-09-20 16:53:57 +0900330clean_up() {
Saswat Padhibf8a9cb2024-12-04 02:32:33 +0000331 [ "$save_workdir" -eq 1 ] || rm -rf "${workdir}"
Jiyong Parka128bad2024-09-20 16:53:57 +0900332}
333
334set -e
335trap clean_up EXIT
336
337built_image=image.raw
338workdir=$(mktemp -d)
Jiyong Park879ee4a2024-11-29 14:00:47 +0900339build_id=$(prepare_build_id)
Jiyong Parka128bad2024-09-20 16:53:57 +0900340debian_cloud_image=${workdir}/debian_cloud_image
Jiyong Park44dd28f2024-09-20 18:47:40 +0900341debian_version=bookworm
342config_space=${debian_cloud_image}/config_space/${debian_version}
Jeongik Cha37047c32024-09-20 23:09:16 +0900343resources_dir=${debian_cloud_image}/src/debian_cloud_images/resources
Saswat Padhibf8a9cb2024-12-04 02:32:33 +0000344arch="$(uname -m)"
Jeongik Cha06f4ac52024-11-12 15:56:05 +0900345mode=debug
Saswat Padhi26c4ef32024-11-29 19:46:53 +0000346save_workdir=0
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000347use_custom_kernel=0
Jiyong Park879ee4a2024-11-29 14:00:47 +0900348
maciek swiech0fdd0512024-10-11 15:12:44 +0000349parse_options "$@"
Jiyong Parka128bad2024-09-20 16:53:57 +0900350check_sudo
Jiyong Parka128bad2024-09-20 16:53:57 +0900351install_prerequisites
352download_debian_cloud_image
Jiyong Park44dd28f2024-09-20 18:47:40 +0900353copy_android_config
Saswat Padhiac62a8b2024-12-06 00:48:07 +0000354package_custom_kernel
Jiyong Park0e565ed2024-09-24 12:39:53 +0900355run_fai
maciek swiech3919b8c2024-11-19 20:58:32 +0000356fdisk -l "${built_image}"
Mu-Le Lee955b6582024-11-01 15:40:58 +0800357images=()
358
maciek swieche17e59f2024-11-25 20:13:23 +0000359cp "$(dirname "$0")/vm_config.json.${arch}" vm_config.json
360
361extract_partitions
Mu-Le Lee955b6582024-11-01 15:40:58 +0800362
363if [[ "$arch" == "aarch64" ]]; then
Mu-Le Lee955b6582024-11-01 15:40:58 +0800364 images+=(
365 root_part
366 efi_part
367 )
Jeongik Cha8e711982024-10-20 12:45:35 +0900368# TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
maciek swieche17e59f2024-11-25 20:13:23 +0000369elif [[ "$arch" == "x86_64" ]]; then
Saswat Padhida6fb072024-11-27 23:07:31 +0000370 rm -f vmlinuz initrd.img
maciek swiech3919b8c2024-11-19 20:58:32 +0000371 virt-get-kernel -a "${built_image}"
Jeongik Cha8e711982024-10-20 12:45:35 +0900372 mv vmlinuz* vmlinuz
373 mv initrd.img* initrd.img
374 images+=(
Jeongik Cha53f696d2024-11-27 01:31:03 +0000375 bios_part
maciek swieche17e59f2024-11-25 20:13:23 +0000376 root_part
377 efi_part
Jeongik Cha8e711982024-10-20 12:45:35 +0900378 vmlinuz
379 initrd.img
380 )
381fi
Jeongik Cha904d9622024-10-21 11:16:37 +0900382
Jeongik Cha8e711982024-10-20 12:45:35 +0900383# --sparse option isn't supported in apache-commons-compress
Jiyong Park879ee4a2024-11-29 14:00:47 +0900384tar czv -f images.tar.gz ${build_id} "${images[@]}" vm_config.json