From f9aef172be43e6ed48d9fa4c877b4035420949e2 Mon Sep 17 00:00:00 2001 From: Julio Montes Date: Mon, 9 Jul 2018 14:31:50 -0500 Subject: [PATCH 1/2] snap: support arm and ppc architectures Use `arch` to identify qemu architecture instead of hardcoding it. fixes #91 Signed-off-by: Julio Montes --- snap/snapcraft.yaml.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/snap/snapcraft.yaml.in b/snap/snapcraft.yaml.in index ab92409a..cb2a698f 100644 --- a/snap/snapcraft.yaml.in +++ b/snap/snapcraft.yaml.in @@ -25,8 +25,9 @@ parts: unset GOROOT export GOPATH=$(realpath ../go) cd ${GOPATH}/src/github.com/${SNAPCRAFT_PROJECT_NAME}/runtime + QEMU_ARCH=$(arch) make \ - QEMUPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/bin/qemu-system-x86_64 \ + QEMUPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/bin/qemu-system-${QEMU_ARCH} \ PROXYPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/libexec/${SNAPCRAFT_PROJECT_NAME}/kata-proxy \ SHIMPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/libexec/${SNAPCRAFT_PROJECT_NAME}/kata-shim \ KERNELPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/share/${SNAPCRAFT_PROJECT_NAME}/vmlinuz.container \ @@ -35,7 +36,7 @@ parts: make install \ PREFIX=/usr \ DESTDIR=${SNAPCRAFT_PART_INSTALL} \ - QEMUPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/bin/qemu-system-x86_64 \ + QEMUPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/bin/qemu-system-${QEMU_ARCH} \ PROXYPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/libexec/${SNAPCRAFT_PROJECT_NAME}/kata-proxy \ SHIMPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/libexec/${SNAPCRAFT_PROJECT_NAME}/kata-shim \ KERNELPATH=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/share/${SNAPCRAFT_PROJECT_NAME}/vmlinuz.container \ From a8a4e15951c8f4024e77e03a980b5bf6c8c39a95 Mon Sep 17 00:00:00 2001 From: Julio Montes Date: Fri, 13 Jul 2018 09:37:45 -0500 Subject: [PATCH 2/2] 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 --- .gitignore | 5 ++ Makefile | 3 + snap-build/README.md | 11 +++ snap-build/config_amd64.sh | 20 +++++ snap-build/config_arm64.sh | 15 ++++ snap-build/config_ppc64.sh | 15 ++++ snap-build/lib.sh | 115 +++++++++++++++++++++++++ snap-build/seed/meta-data | 2 + snap-build/seed/user-data.in | 21 +++++ snap-build/snap.sh | 48 +++++++++++ snap-build/xbuild.sh | 157 +++++++++++++++++++++++++++++++++++ 11 files changed, 412 insertions(+) create mode 100644 snap-build/README.md create mode 100755 snap-build/config_amd64.sh create mode 100755 snap-build/config_arm64.sh create mode 100755 snap-build/config_ppc64.sh create mode 100644 snap-build/lib.sh create mode 100644 snap-build/seed/meta-data create mode 100644 snap-build/seed/user-data.in create mode 100755 snap-build/snap.sh create mode 100755 snap-build/xbuild.sh diff --git a/.gitignore b/.gitignore index 0d6184c0..75ff735d 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/Makefile b/Makefile index abc3d78e..35ebb5c0 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/snap-build/README.md b/snap-build/README.md new file mode 100644 index 00000000..3e02612b --- /dev/null +++ b/snap-build/README.md @@ -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 +``` diff --git a/snap-build/config_amd64.sh b/snap-build/config_amd64.sh new file mode 100755 index 00000000..8bdad3f3 --- /dev/null +++ b/snap-build/config_amd64.sh @@ -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 diff --git a/snap-build/config_arm64.sh b/snap-build/config_arm64.sh new file mode 100755 index 00000000..02b50092 --- /dev/null +++ b/snap-build/config_arm64.sh @@ -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="" diff --git a/snap-build/config_ppc64.sh b/snap-build/config_ppc64.sh new file mode 100755 index 00000000..cda28179 --- /dev/null +++ b/snap-build/config_ppc64.sh @@ -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" diff --git a/snap-build/lib.sh b/snap-build/lib.sh new file mode 100644 index 00000000..f7df207d --- /dev/null +++ b/snap-build/lib.sh @@ -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 +} diff --git a/snap-build/seed/meta-data b/snap-build/seed/meta-data new file mode 100644 index 00000000..06f5fa3c --- /dev/null +++ b/snap-build/seed/meta-data @@ -0,0 +1,2 @@ +instance-id: snapid +local-hostname: snap diff --git a/snap-build/seed/user-data.in b/snap-build/seed/user-data.in new file mode 100644 index 00000000..4fb9339d --- /dev/null +++ b/snap-build/seed/user-data.in @@ -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 diff --git a/snap-build/snap.sh b/snap-build/snap.sh new file mode 100755 index 00000000..48d7e399 --- /dev/null +++ b/snap-build/snap.sh @@ -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 diff --git a/snap-build/xbuild.sh b/snap-build/xbuild.sh new file mode 100755 index 00000000..8c338a2e --- /dev/null +++ b/snap-build/xbuild.sh @@ -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 , 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 "$@"