snap-build: implement system to cross-build snap images

Add scripts to cross-build snap images for all supported
architectures using virtual machines

fixes #98

Signed-off-by: Julio Montes <julio.montes@intel.com>
This commit is contained in:
Julio Montes 2018-07-13 09:37:45 -05:00
parent f9aef172be
commit a8a4e15951
11 changed files with 412 additions and 0 deletions

5
.gitignore vendored
View File

@ -9,3 +9,8 @@ prime/
stage/
snap/.snapcraft/
snap/snapcraft.yaml
snap-build/*.log
snap-build/*.img
snap-build/*.fd
snap-build/id_rsa*
snap-build/seed/user-data

View File

@ -59,6 +59,9 @@ $(SNAPCRAFT_FILE): %: %.in Makefile $(YQ) $(VERSIONS_YAML_FILE) $(VERSION_FILE)
snap: $(SNAPCRAFT_FILE)
snapcraft -d
snap-xbuild:
cd $(MK_DIR)/snap-build; ./xbuild.sh -a all
clean:
rm $(SNAPCRAFT_FILE)

11
snap-build/README.md Normal file
View File

@ -0,0 +1,11 @@
# Cross-build snap images
Build Kata Containers snap images for all supported architectures using virtual machines.
## Usage
Run following command to build the snap images for all supported images.
```
./xbuild.sh -a all
```

20
snap-build/config_amd64.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
local arch_qemu="x86_64"
local arch_image="bionic-server-cloudimg-amd64.img"
local arch_image_url="https://cloud-images.ubuntu.com/bionic/current/${arch_image}"
local arch_bios=""
local arch_bios_url=""
local arch_qemu_cpu="qemu64"
local arch_qemu_machine="pc"
local arch_qemu_extra_opts=""
if [ "$(arch)" == "x86_64" ];then
arch_qemu_cpu="host"
arch_qemu_machine="pc,accel=kvm"
arch_qemu_extra_opts="-enable-kvm"
fi

15
snap-build/config_arm64.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
local arch_qemu="aarch64"
local arch_image="bionic-server-cloudimg-arm64.img"
local arch_image_url="https://cloud-images.ubuntu.com/bionic/current/${arch_image}"
local arch_bios="QEMU_EFI.fd"
local arch_bios_url="https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/${arch_bios}"
local arch_qemu_cpu="cortex-a57"
local arch_qemu_machine="virt,usb=off"
local arch_qemu_extra_opts=""

15
snap-build/config_ppc64.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
local arch_qemu="ppc64"
local arch_image="bionic-server-cloudimg-ppc64el.img"
local arch_image_url="https://cloud-images.ubuntu.com/bionic/current/${arch_image}"
local arch_bios="QEMU_EFI.fd"
local arch_bios_url="https://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/${arch_bios}"
local arch_qemu_cpu="POWER8"
local arch_qemu_machine="pseries,usb=off"
local arch_qemu_extra_opts="-echr 0x05 -boot c"

115
snap-build/lib.sh Normal file
View File

@ -0,0 +1,115 @@
#!/bin/bash
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
error(){
msg="$*"
echo "ERROR: $msg" >&2
}
die(){
error "$*"
exit 1
}
make_random_ip_addr() {
echo "127.$((1 + RANDOM % 240)).$((1 + RANDOM % 240)).$((1 + RANDOM % 240))"
}
make_random_port() {
echo "$((11060 + RANDOM % 1000))"
}
get_dnssearch() {
echo "$(grep search /etc/resolv.conf | cut -d' ' -f 2)"
}
get_dns() {
v="$(grep nameserver /etc/resolv.conf | cut -d' ' -f2 | sed -e 's/^/"/g' -e 's/$/",/g')"
echo ${v} | sed -e 's|,$||g'
}
download() {
url="$1"
outdir="$2"
pushd "${outdir}"
curl -LO ${url}
ret=$?
popd
return ${ret}
}
setup_image() {
img_url=$1
img=$2
[ -f "${img}" ] && return
{ download "${img_url}" "$(dirname ${img})"; ret=$?; } || true
[ ${ret} != 0 ] && rm -f "${img}" && return
qemu-img resize "${img}" +5G
}
# arg1: ip
# arg2: port
# arg3: ssh key
# arg4: timeout in minutes
# return: 0 on success, 1 otherwise
ping_vm() {
ip="$1"
port="$2"
sshkeyfile="$3"
timeout=$4
minute=60
sleeptime=10
timeoutsec=$((timeout*minute))
tries=$((timeoutsec/sleeptime))
for i in $(seq 1 ${tries}); do
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i "${sshkeyfile}" "${ip}" -p "${port}" true && return 0
sleep ${sleeptime}
done
return 1
}
# arg1: qemu system: ppc64, aarch64 or x86_64
# arg2: cpu model
# arg3: machine type
# arg4: ip
# arg5: port
# arg6: image path
# arg7: seed image path
# arg8: extra options
run_qemu() {
local arch="${1}"
local cpu="${2}"
local machine="${3}"
local ip="${4}"
local port="${5}"
local image="${6}"
local seed_img="${7}"
local extra_opts="${8}"
local ssh_key_file="id_rsa"
local ping_timeout=15
local img_opts="-drive file=${image},if=virtio,format=qcow2,aio=threads"
local seed_opts="-drive file=${seed_img},if=virtio,media=cdrom"
if [ "${arch}" == "aarch64" ]; then
img_opts="-device virtio-blk-device,drive=image -drive file=${image},if=none,id=image,aio=threads"
seed_opts="-device virtio-blk-device,drive=cloud -drive file=${seed_img},if=none,id=cloud,format=raw"
fi
qemu-system-${arch} -cpu "${cpu}" -machine "${machine}" -smp cpus=4 -m 2048M \
-net nic,model=virtio -device virtio-rng-pci -net user,hostfwd=tcp:${ip}:${port}-:22,dnssearch="$(get_dnssearch)" \
${img_opts} ${seed_opts} \
-display none -vga none -daemonize ${extra_opts}
[ $? != 0 ] && return 1
# depending of the host's hw, it takes for around ~15 minutes
ping_vm "${ip}" "${port}" "${ssh_key_file}" ${ping_timeout}
[ $? != 0 ] && return 1
return 0
}

View File

@ -0,0 +1,2 @@
instance-id: snapid
local-hostname: snap

View File

@ -0,0 +1,21 @@
#cloud-config
@APT_PROXY@
package_upgrade: false
users:
- lock-passwd: true
name: @USER@
shell: /bin/bash
ssh-authorized-keys:
- @SSH_KEY@
sudo: ALL=(ALL) NOPASSWD:ALL
write_files:
- content: |
[Service]
Environment=@DOCKER_ENV@
path: /etc/systemd/system/docker.service.d/http-proxy.conf
- content: |
@ENV@
path: /etc/environment
- content: |
{"dns": [@DOCKER_DNS@]}
path: /etc/docker/daemon.json

48
snap-build/snap.sh Executable file
View File

@ -0,0 +1,48 @@
#!/bin/bash
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
# Setup the environment and build the snap image.
# This script runs in the VM.
set -x -e
sudo apt-get update -y
sudo apt-get install -y \
build-essential \
cpio \
docker.io \
golang-go \
libattr1-dev \
libcap-dev \
libcap-ng-dev \
libdw-dev \
libelf-dev \
libfdt-dev \
libglib2.0-dev \
libiberty-dev \
libnewt-dev \
libpci-dev \
libpixman-1-dev \
librbd-dev \
libssl-dev \
libz-dev \
openssl \
python \
snapcraft \
snapd
# start docker
sudo systemctl start docker
# clone packaging reposiory and make snap
packaging_repo_url=https://github.com/kata-containers/packaging
packaging_dir=~/packaging
sudo rm -rf ${packaging_dir}
git clone ${packaging_repo_url} ${packaging_dir}
pushd ${packaging_dir}
sudo -E PATH=$PATH make snap
sudo chown ${USER}:${USER} *.snap

157
snap-build/xbuild.sh Executable file
View File

@ -0,0 +1,157 @@
#!/bin/bash
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
# Build in parallel snap images using VMs.
# This script runs in the host.
source lib.sh
readonly supported_archs=(all amd64 ppc64 arm64)
seed_dir=seed
seed_img=seed.img
id_rsa_file=id_rsa
id_rsa_pub_file=id_rsa.pub
snap_sh=snap.sh
ssh="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i ${id_rsa_file}"
scp="scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i ${id_rsa_file}"
gen_seed() {
rm -f "${seed_img}"
truncate --size 2M "${seed_img}"
mkfs.vfat -n cidata "${seed_img}" &> /dev/null
if [ -n "${http_proxy}" ]; then
apt_proxy="apt:\n https_proxy: ${https_proxy}\n proxy: ${http_proxy}"
docker_env="\"HTTP_PROXY=${http_proxy}\" \"HTTPS_PROXY=${https_proxy}\" \"NO_PROXY=${no_proxy}\""
env="no_proxy=${no_proxy}\n\
NO_PROXY=${no_proxy}\n\
http_proxy=${http_proxy}\n\
HTTP_PROXY=${http_proxy}\n\
https_proxy=${https_proxy}\n\
HTTPS_PROXY=${https_proxy}"
fi
docker_dns="$(get_dns)"
[ ! -f "${id_rsa_file}" ] && ssh-keygen -t rsa -f ${id_rsa_file} -P '' &> /dev/null
ssh_key="$(cat ${id_rsa_pub_file})"
sed \
-e "s|@USER@|""${USER}""|g" \
-e "s|@SSH_KEY@|""${ssh_key}""|g" \
-e "s|@APT_PROXY@|""${apt_proxy}""|g" \
-e "s|@DOCKER_ENV@|""${docker_env}""|g" \
-e "s|@DOCKER_DNS@|""${docker_dns}""|g" \
-e "s|@ENV@|""${env}""|g" \
${seed_dir}/user-data.in > ${seed_dir}/user-data
mcopy -oi "${seed_img}" ${seed_dir}/user-data ${seed_dir}/meta-data ::
}
poweroff_and_die() {
ip="$1"
port="$2"
${ssh} "${ip}" -p "${port}" sudo poweroff
die "$3"
}
build_arch() {
set -x -e
local arch="$1"
source "config_${arch}.sh"
local ip="$(make_random_ip_addr)"
local port="$(make_random_port)"
setup_image "${arch_image_url}" "${arch_image}"
# download bios if needed
if [ -n "${arch_bios}" ] && [ -n "${arch_bios_url}" ]; then
arch_qemu_extra_opts+=" -bios ${arch_bios}"
[ -f "${arch_bios}" ] || download "${arch_bios_url}" "."
fi
# run QEMU
run_qemu "${arch_qemu}" \
"${arch_qemu_cpu}" \
"${arch_qemu_machine}" \
"${ip}" \
"${port}" \
"${arch_image}" \
"${seed_img}" \
"${arch_qemu_extra_opts}"
# copy snap script to VM
${scp} -P "${port}" "${snap_sh}" "${ip}:~/" || poweroff_and_die "${ip}" "${port}" "Could not copy snap script"
# run snap script in the VM
${ssh} "${ip}" -p "${port}" "~/snap.sh" || poweroff_and_die "${ip}" "${port}" "Failed to run build script"
# copy snap image from VM
${scp} -P "${port}" "${ip}:~/packaging/*.snap" . || poweroff_and_die "${ip}" "${port}" "Failed to get snap image"
# poweroff VM
${ssh} "${ip}" -p "${port}" sudo poweroff
}
help()
{
usage=$(cat << EOF
Usage: $0 [-h] [options]
Description:
Build snap images.
Options:
-a <arch>, Build snap image for all or a specific architecture (mandatory).
-h, Show this help text and exit.
Supported architectures:
$(IFS=$'\t'; echo -e "${supported_archs[*]}")
EOF
)
echo "$usage"
}
main() {
local arch
local OPTIND
while getopts "a:h" opt; do
case ${opt} in
a)
arch="${OPTARG}"
;;
h)
help
exit 0;
;;
?)
# parse failure
help
die "Failed to parse arguments"
;;
esac
done
shift $((OPTIND-1))
[ -z "${arch}" ] && help && die "Mandatory architecture not supplied"
if ! [[ " ${supported_archs[@]} " =~ " ${arch} " ]]; then
help
die "Architecture '${arch}' not supported"
fi
gen_seed
if [ "${arch}" != "all" ]; then
build_arch "${arch}" &> "${arch}.log"
else
for a in ${supported_archs[@]}; do
(build_arch "${a}" &> "${a}.log") &
done
wait
fi
}
main "$@"