name: kata-containers
summary: Build lightweight VMs that seamlessly plug into the containers ecosystem
description: |
  Kata Containers is an open source project and community working to build a
  standard implementation of lightweight Virtual Machines (VMs) that feel and
  perform like containers, but provide the workload isolation and security
  advantages of VMs
confinement: classic
adopt-info: metadata
base: core20

parts:
  metadata:
    plugin: nil
    prime:
      - -*
    build-packages:
      - git
      - git-extras
    override-pull: |
      version="9999"
      kata_url="https://github.com/kata-containers/kata-containers"

      if echo "${GITHUB_REF}" | grep -q -E "^refs/tags"; then
        version=$(echo ${GITHUB_REF} | cut -d/ -f3)
        git checkout ${version}
      fi

      snapcraftctl set-grade "stable"
      snapcraftctl set-version "${version}"

      # setup GOPATH - this repo dir should be there
      export GOPATH=${SNAPCRAFT_STAGE}/gopath
      kata_dir=${GOPATH}/src/github.com/${SNAPCRAFT_PROJECT_NAME}/${SNAPCRAFT_PROJECT_NAME}
      mkdir -p $(dirname ${kata_dir})
      ln -sf $(realpath "${SNAPCRAFT_STAGE}/..") ${kata_dir}

  godeps:
    after: [metadata]
    plugin: nil
    prime:
      - -*
    build-packages:
      - curl
    override-build: |
      # put everything in stage
      cd ${SNAPCRAFT_STAGE}

      yq_path="./yq"
      yq_pkg="github.com/mikefarah/yq"
      goos="linux"
      case "$(uname -m)" in
        aarch64) goarch="arm64";;
        ppc64le) goarch="ppc64le";;
        x86_64) goarch="amd64";;
        s390x) goarch="s390x";;
        *) echo "unsupported architecture: $(uname -m)"; exit 1;;
      esac

      yq_version=3.4.1
      yq_url="https://${yq_pkg}/releases/download/${yq_version}/yq_${goos}_${goarch}"
      curl -o "${yq_path}" -L "${yq_url}"
      chmod +x "${yq_path}"

      kata_dir=gopath/src/github.com/${SNAPCRAFT_PROJECT_NAME}/${SNAPCRAFT_PROJECT_NAME}
      version="$(${yq_path} r ${kata_dir}/versions.yaml languages.golang.meta.newest-version)"
      tarfile="go${version}.${goos}-${goarch}.tar.gz"
      curl -LO https://golang.org/dl/${tarfile}
      tar -xf ${tarfile} --strip-components=1

  image:
    after: [godeps, qemu, kernel]
    plugin: nil
    build-packages:
      - docker.io
      - cpio
      - git
      - iptables
      - software-properties-common
      - uidmap
      - gnupg2
    override-build: |
      [ "$(uname -m)" = "ppc64le" ] || [ "$(uname -m)" = "s390x" ] && sudo apt-get --no-install-recommends install -y protobuf-compiler

      yq=${SNAPCRAFT_STAGE}/yq

      # set GOPATH
      export GOPATH=${SNAPCRAFT_STAGE}/gopath
      kata_dir=${GOPATH}/src/github.com/${SNAPCRAFT_PROJECT_NAME}/${SNAPCRAFT_PROJECT_NAME}

      export GOROOT=${SNAPCRAFT_STAGE}
      export PATH="${GOROOT}/bin:${PATH}"
      export GO111MODULE="auto"

      http_proxy=${http_proxy:-""}
      https_proxy=${https_proxy:-""}
      if [ -n "$http_proxy" ]; then
        echo "Setting proxy $http_proxy"
        sudo -E systemctl set-environment http_proxy=$http_proxy || true
        sudo -E systemctl set-environment https_proxy=$https_proxy || true
      fi

      # Copy yq binary. It's used in the container
      mkdir -p "${GOPATH}/bin/"
      cp -a "${yq}" "${GOPATH}/bin/"

      echo "Unmasking docker service"
      sudo -E systemctl unmask docker.service || true
      sudo -E systemctl unmask docker.socket || true
      echo "Adding $USER into docker group"
      sudo -E gpasswd -a $USER docker
      echo "Starting docker"
      sudo -E systemctl start docker || true

      cd ${kata_dir}/tools/osbuilder

      # build image
      export AGENT_INIT=yes
      export USE_DOCKER=1
      export DEBUG=1
      arch="$(uname -m)"
      initrd_distro=$(${yq} r -X ${kata_dir}/versions.yaml assets.initrd.architecture.${arch}.name)
      image_distro=$(${yq} r -X ${kata_dir}/versions.yaml assets.image.architecture.${arch}.name)
      case "$arch" in
        x86_64)
          # In some build systems it's impossible to build a rootfs image, try with the initrd image
          sudo -E PATH=$PATH make image DISTRO=${image_distro} || sudo -E PATH=$PATH make initrd DISTRO=${initrd_distro}
        ;;

        aarch64|ppc64le|s390x)
          sudo -E PATH=$PATH make initrd DISTRO=${initrd_distro}
        ;;

        *) echo "unsupported architecture: $(uname -m)"; exit 1;;
      esac

      # Install image
      kata_image_dir=${SNAPCRAFT_PART_INSTALL}/usr/share/kata-containers
      mkdir -p ${kata_image_dir}
      cp kata-containers*.img ${kata_image_dir}

  runtime:
    after: [godeps, image, cloud-hypervisor]
    plugin: nil
    build-attributes: [no-patchelf]
    override-build: |
      # set GOPATH
      export GOPATH=${SNAPCRAFT_STAGE}/gopath
      export GOROOT=${SNAPCRAFT_STAGE}
      export PATH="${GOROOT}/bin:${PATH}"
      export GO111MODULE="auto"
      kata_dir=${GOPATH}/src/github.com/${SNAPCRAFT_PROJECT_NAME}/${SNAPCRAFT_PROJECT_NAME}

      cd ${kata_dir}/src/runtime

      # setup arch
      arch=$(uname -m)
      if [ ${arch} = "ppc64le" ]; then
        arch="ppc64"
      fi

      # build and install runtime
      make \
        PREFIX=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr \
        SKIP_GO_VERSION_CHECK=1 \
        QEMUCMD=qemu-system-$arch
      make install \
        PREFIX=/usr \
        DESTDIR=${SNAPCRAFT_PART_INSTALL} \
        SKIP_GO_VERSION_CHECK=1 \
        QEMUCMD=qemu-system-$arch

      if [ ! -f ${SNAPCRAFT_PART_INSTALL}/../../image/install/usr/share/kata-containers/kata-containers.img ]; then
        sed -i -e "s|^image =.*|initrd = \"/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr/share/kata-containers/kata-containers-initrd.img\"|" \
          ${SNAPCRAFT_PART_INSTALL}/usr/share/defaults/${SNAPCRAFT_PROJECT_NAME}/configuration.toml
      fi

  kernel:
    after: [godeps]
    plugin: nil
    build-packages:
      - libelf-dev
      - curl
      - build-essential
      - bison
      - flex
    override-build: |
      yq=${SNAPCRAFT_STAGE}/yq
      export PATH="${PATH}:${SNAPCRAFT_STAGE}"
      export GOPATH=${SNAPCRAFT_STAGE}/gopath
      kata_dir=${GOPATH}/src/github.com/${SNAPCRAFT_PROJECT_NAME}/${SNAPCRAFT_PROJECT_NAME}
      versions_file="${kata_dir}/versions.yaml"
      kernel_version="$(${yq} r $versions_file assets.kernel.version)"
      #Remove extra 'v'
      kernel_version=${kernel_version#v}

      [ "$(uname -m)" = "s390x" ] && sudo apt-get --no-install-recommends install -y libssl-dev

      export GOPATH=${SNAPCRAFT_STAGE}/gopath
      export GO111MODULE="auto"
      kata_dir=${GOPATH}/src/github.com/${SNAPCRAFT_PROJECT_NAME}/${SNAPCRAFT_PROJECT_NAME}

      cd ${kata_dir}/tools/packaging/kernel
      kernel_dir_prefix="kata-linux-"

      # Setup and build kernel
      ./build-kernel.sh -v ${kernel_version} -d setup
      cd ${kernel_dir_prefix}*
      make -j $(($(nproc)-1)) EXTRAVERSION=".container"

      kernel_suffix=${kernel_version}.container
      kata_kernel_dir=${SNAPCRAFT_PART_INSTALL}/usr/share/kata-containers
      mkdir -p ${kata_kernel_dir}

      # Install bz kernel
      make install INSTALL_PATH=${kata_kernel_dir} EXTRAVERSION=".container" || true
      vmlinuz_name=vmlinuz-${kernel_suffix}
      ln -sf ${vmlinuz_name} ${kata_kernel_dir}/vmlinuz.container

      # Install raw kernel
      vmlinux_path=vmlinux
      [ "$(uname -m)" = "s390x" ] && vmlinux_path=arch/s390/boot/compressed/vmlinux
      vmlinux_name=vmlinux-${kernel_suffix}
      cp ${vmlinux_path} ${kata_kernel_dir}/${vmlinux_name}
      ln -sf ${vmlinux_name} ${kata_kernel_dir}/vmlinux.container

  qemu:
    plugin: make
    after: [godeps]
    build-packages:
      - gcc
      - python3
      - zlib1g-dev
      - libcap-ng-dev
      - libglib2.0-dev
      - libpixman-1-dev
      - libnuma-dev
      - libltdl-dev
      - libcap-dev
      - libattr1-dev
      - libfdt-dev
      - curl
      - libcapstone-dev
      - bc
      - libblkid-dev
      - libffi-dev
      - libmount-dev
      - libseccomp-dev
      - libselinux1-dev
      - ninja-build
    override-build: |
      yq=${SNAPCRAFT_STAGE}/yq
      export GOPATH=${SNAPCRAFT_STAGE}/gopath
      export GO111MODULE="auto"
      kata_dir=${GOPATH}/src/github.com/${SNAPCRAFT_PROJECT_NAME}/${SNAPCRAFT_PROJECT_NAME}

      versions_file="${kata_dir}/versions.yaml"
      branch="$(${yq} r ${versions_file} assets.hypervisor.qemu.version)"
      url="$(${yq} r ${versions_file} assets.hypervisor.qemu.url)"
      commit=""
      patches_dir="${kata_dir}/tools/packaging/qemu/patches/$(echo ${branch} | sed -e 's/.[[:digit:]]*$//' -e 's/^v//').x"
      patches_version_dir="${kata_dir}/tools/packaging/qemu/patches/tag_patches/${branch}"

      # download source
      qemu_dir=${SNAPCRAFT_STAGE}/qemu
      rm -rf "${qemu_dir}"
      git clone --depth 1 --branch ${branch} --single-branch ${url} "${qemu_dir}"
      cd ${qemu_dir}
      [ -z "${commit}" ] || git checkout ${commit}

      [ -n "$(ls -A ui/keycodemapdb)" ] || git clone --depth 1 https://github.com/qemu/keycodemapdb ui/keycodemapdb/
      [ -n "$(ls -A capstone)" ] || git clone --depth 1 https://github.com/qemu/capstone capstone

      # Apply branch patches
      [ -d "${patches_version_dir}" ] || mkdir "${patches_version_dir}"
      ${kata_dir}/tools/packaging/scripts/apply_patches.sh "${patches_dir}"
      ${kata_dir}/tools/packaging/scripts/apply_patches.sh "${patches_version_dir}"

      # Only x86_64 supports libpmem
      [ "$(uname -m)" = "x86_64" ] && sudo apt-get --no-install-recommends install -y apt-utils ca-certificates libpmem-dev

      configure_hypervisor=${kata_dir}/tools/packaging/scripts/configure-hypervisor.sh
      chmod +x ${configure_hypervisor}
      # static build. The --prefix, --libdir, --libexecdir, --datadir arguments are
      # based on PREFIX and set by configure-hypervisor.sh
      echo "$(PREFIX=/snap/${SNAPCRAFT_PROJECT_NAME}/current/usr ${configure_hypervisor} -s kata-qemu) \
        --disable-rbd " \
        | xargs ./configure

      # Copy QEMU configurations (Kconfigs)
      case "${branch}" in
      "v5.1.0")
        cp -a ${kata_dir}/tools/packaging/qemu/default-configs/* default-configs
        ;;

      *)
        cp -a ${kata_dir}/tools/packaging/qemu/default-configs/* configs/devices/
        ;;
      esac

      # build and install
      make -j $(($(nproc)-1))
      make install DESTDIR=${SNAPCRAFT_PART_INSTALL}
    prime:
      - -snap/
      - -usr/bin/qemu-ga
      - -usr/bin/qemu-pr-helper
      - -usr/bin/virtfs-proxy-helper
      - -usr/include/
      - -usr/share/applications/
      - -usr/share/icons/
      - -usr/var/
      - usr/*
      - lib/*
    organize:
      # Hack: move qemu to /
      "snap/kata-containers/current/": "./"

  cloud-hypervisor:
    plugin: nil
    after: [godeps]
    override-build: |
      arch=$(uname -m)
      if [ "{$arch}" == "aarch64" ] || [ "${arch}" == "x64_64" ]; then 
          sudo apt-get -y update
          sudo apt-get -y install ca-certificates curl gnupg lsb-release
          curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
          echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
          sudo apt-get -y update
          sudo apt-get -y install docker-ce docker-ce-cli containerd.io
          sudo systemctl start docker.socket

          export GOPATH=${SNAPCRAFT_STAGE}/gopath
          kata_dir=${GOPATH}/src/github.com/${SNAPCRAFT_PROJECT_NAME}/${SNAPCRAFT_PROJECT_NAME}
          cd ${kata_dir}
          sudo -E NO_TTY=true make cloud-hypervisor-tarball
          tar xvJpf build/kata-static-cloud-hypervisor.tar.xz -C /tmp/
          install -D /tmp/opt/kata/bin/cloud-hypervisor ${SNAPCRAFT_PART_INSTALL}/usr/bin/cloud-hypervisor
      fi

apps:
  runtime:
    command: usr/bin/kata-runtime
  shim:
    command: usr/bin/containerd-shim-kata-v2
  collect-data:
    command: usr/bin/kata-collect-data.sh
