blob: 19894c2c6a6c608b95b00a2ba0c173aee0e4020a [file] [log] [blame] [edit]
#!/bin/bash
# This is a script to build a Debian image that can run in a VM created via AVF.
# TODOs:
# - Add Android-specific packages via a new class
# - Use a stable release from debian-cloud-images
show_help() {
echo "Usage: sudo $0 [OPTION]... [FILE]"
echo "Builds a debian image and save it to FILE. [sudo is required]"
echo "Options:"
echo "-h Print usage and this help message and exit."
echo "-a ARCH Architecture of the image [default is host arch: $(uname -m)]"
echo "-r Release mode build"
echo "-w Save temp work directory [for debugging]"
}
check_sudo() {
if [ "$EUID" -ne 0 ]; then
echo "Please run as root." ; exit 1
fi
}
parse_options() {
while getopts "a:hrw" option; do
case ${option} in
h)
show_help ; exit
;;
a)
arch="$OPTARG"
;;
r)
mode=release
;;
w)
save_workdir=1
;;
*)
echo "Invalid option: $OPTARG" ; exit 1
;;
esac
done
case "$arch" in
aarch64)
debian_arch="arm64"
;;
x86_64)
debian_arch="amd64"
;;
*)
echo "Invalid architecture: $arch" ; exit 1
;;
esac
if [[ "${*:$OPTIND:1}" ]]; then
built_image="${*:$OPTIND:1}"
fi
}
prepare_build_id() {
local filename=build_id
if [ -z "${KOKORO_BUILD_NUMBER}" ]; then
echo eng-$(hostname)-$(date --utc) > ${filename}
else
echo ${KOKORO_BUILD_NUMBER} > ${filename}
fi
echo ${filename}
}
install_prerequisites() {
apt update
packages=(
apt-utils
automake
binfmt-support
build-essential
ca-certificates
cmake
curl
debsums
dosfstools
fai-server
fai-setup-storage
fdisk
git
libjson-c-dev
libtool
libwebsockets-dev
make
protobuf-compiler
python3
python3-libcloud
python3-marshmallow
python3-pytest
python3-yaml
qemu-user-static
qemu-utils
sudo
udev
)
if [[ "$arch" == "aarch64" ]]; then
packages+=(
gcc-aarch64-linux-gnu
libc6-dev-arm64-cross
qemu-system-arm
)
else
packages+=(
qemu-system
)
fi
# TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
if [[ "$arch" == "x86_64" ]]; then
packages+=(
libguestfs-tools
linux-image-generic
)
fi
DEBIAN_FRONTEND=noninteractive \
apt install --no-install-recommends --assume-yes "${packages[@]}"
if [ ! -f $"HOME"/.cargo/bin/cargo ]; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
fi
source "$HOME"/.cargo/env
rustup target add "${arch}"-unknown-linux-gnu
cargo install cargo-license
}
download_debian_cloud_image() {
local ver=master
local prj=debian-cloud-images
local url="https://salsa.debian.org/cloud-team/${prj}/-/archive/${ver}/${prj}-${ver}.tar.gz"
local outdir="${debian_cloud_image}"
mkdir -p "${outdir}"
wget -O - "${url}" | tar xz -C "${outdir}" --strip-components=1
}
build_rust_binary_and_copy() {
pushd "$(dirname "$0")/../../guest/$1" > /dev/null
local release_flag=
local artifact_mode=debug
if [[ "$mode" == "release" ]]; then
release_flag="--release"
artifact_mode=release
fi
RUSTFLAGS="-C linker=${arch}-linux-gnu-gcc" cargo build \
--target "${arch}-unknown-linux-gnu" \
--target-dir "${workdir}/$1" ${release_flag}
mkdir -p "${dst}/files/usr/local/bin/$1"
cp "${workdir}/$1/${arch}-unknown-linux-gnu/${artifact_mode}/$1" "${dst}/files/usr/local/bin/$1/AVF"
chmod 777 "${dst}/files/usr/local/bin/$1/AVF"
mkdir -p "${dst}/files/usr/share/doc/$1"
cargo license > "${dst}/files/usr/share/doc/$1/copyright"
popd > /dev/null
}
build_ttyd() {
local ttyd_version=1.7.7
local url="https://github.com/tsl0922/ttyd/archive/refs/tags/${ttyd_version}.tar.gz"
cp -r "$(dirname "$0")/ttyd" "${workdir}/ttyd"
pushd "${workdir}" > /dev/null
wget "${url}" -O - | tar xz
cp ttyd/* ttyd-${ttyd_version}/scripts
pushd "$workdir/ttyd-${ttyd_version}" > /dev/null
bash -c "env BUILD_TARGET=${arch} ./scripts/cross-build.sh"
mkdir -p "${dst}/files/usr/local/bin/ttyd"
cp "/tmp/stage/${arch}-linux-musl/bin/ttyd" "${dst}/files/usr/local/bin/ttyd/AVF"
chmod 777 "${dst}/files/usr/local/bin/ttyd/AVF"
mkdir -p "${dst}/files/usr/share/doc/ttyd"
cp LICENSE "${dst}/files/usr/share/doc/ttyd/copyright"
popd > /dev/null
popd > /dev/null
}
copy_android_config() {
local src
local dst
src="$(dirname "$0")/fai_config"
dst="${config_space}"
cp -R "${src}"/* "${dst}"
cp "$(dirname "$0")/image.yaml" "${resources_dir}"
cp -R "$(dirname "$0")/localdebs/" "${debian_cloud_image}/"
build_ttyd
build_rust_binary_and_copy forwarder_guest
build_rust_binary_and_copy forwarder_guest_launcher
build_rust_binary_and_copy ip_addr_reporter
build_rust_binary_and_copy shutdown_runner
}
run_fai() {
local out="${built_image}"
make -C "${debian_cloud_image}" "image_bookworm_nocloud_${debian_arch}"
mv "${debian_cloud_image}/image_bookworm_nocloud_${debian_arch}.raw" "${out}"
}
extract_partitions() {
root_partition_num=1
bios_partition_num=14
efi_partition_num=15
loop=$(losetup -f --show --partscan $built_image)
dd if="${loop}p$root_partition_num" of=root_part
if [[ "$arch" == "x86_64" ]]; then
dd if="${loop}p$bios_partition_num" of=bios_part
fi
dd if="${loop}p$efi_partition_num" of=efi_part
losetup -d "${loop}"
sed -i "s/{root_part_guid}/$(sfdisk --part-uuid $built_image $root_partition_num)/g" vm_config.json
if [[ "$arch" == "x86_64" ]]; then
sed -i "s/{bios_part_guid}/$(sfdisk --part-uuid $built_image $bios_partition_num)/g" vm_config.json
fi
sed -i "s/{efi_part_guid}/$(sfdisk --part-uuid $built_image $efi_partition_num)/g" vm_config.json
}
clean_up() {
[ "$save_workdir" -eq 1 ] || rm -rf "${workdir}"
}
set -e
trap clean_up EXIT
built_image=image.raw
workdir=$(mktemp -d)
build_id=$(prepare_build_id)
debian_cloud_image=${workdir}/debian_cloud_image
debian_version=bookworm
config_space=${debian_cloud_image}/config_space/${debian_version}
resources_dir=${debian_cloud_image}/src/debian_cloud_images/resources
arch="$(uname -m)"
mode=debug
save_workdir=0
parse_options "$@"
check_sudo
install_prerequisites
download_debian_cloud_image
copy_android_config
run_fai
fdisk -l "${built_image}"
images=()
cp "$(dirname "$0")/vm_config.json.${arch}" vm_config.json
extract_partitions
if [[ "$arch" == "aarch64" ]]; then
images+=(
root_part
efi_part
)
# TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
elif [[ "$arch" == "x86_64" ]]; then
rm -f vmlinuz initrd.img
virt-get-kernel -a "${built_image}"
mv vmlinuz* vmlinuz
mv initrd.img* initrd.img
images+=(
bios_part
root_part
efi_part
vmlinuz
initrd.img
)
fi
# --sparse option isn't supported in apache-commons-compress
tar czv -f images.tar.gz ${build_id} "${images[@]}" vm_config.json