xci: scripts: start-new-vm.sh: Use Docker to build OS images 31/43831/6
authorMarkos Chandras <mchandras@suse.de>
Thu, 28 Sep 2017 15:03:01 +0000 (16:03 +0100)
committerMarkos Chandras <mchandras@suse.de>
Mon, 2 Oct 2017 15:18:36 +0000 (16:18 +0100)
Use a docker container to build the OS images so we can build images and
start new virtual machines on all supported operating systems. This way
all developers can now launch a virtual machine to quickly reproduce
Jenkins results which should assist with debugging problems.

Since the container runs with elevated privileges it's best to ensure
that we have exclusive access to devices. Finally, we remove the
build-dib-os.sh script which is now part of the container itself.

The build image process now becomes more stable since it runs on clean
evnironment all the time so the only external factor is the upstream
distribution repositories.

Change-Id: I6b443192419ee2546a23430f421b152766d16333
Signed-off-by: Markos Chandras <mchandras@suse.de>
xci/scripts/vm/build-dib-os.sh [deleted file]
xci/scripts/vm/start-new-vm.sh

diff --git a/xci/scripts/vm/build-dib-os.sh b/xci/scripts/vm/build-dib-os.sh
deleted file mode 100755 (executable)
index a09ee3c..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/bin/bash
-##############################################################################
-# Copyright (c) 2017 SUSE LINUX GmbH.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-##############################################################################
-
-set -e
-
-# This only works on ubuntu hosts
-lsb_release -i | grep -q -i ubuntu || { echo "This script only works on Ubuntu distros"; exit 1; }
-
-declare -A flavors=( ["ubuntu-minimal"]="xenial" ["opensuse-minimal"]="42.3" ["centos-minimal"]="7" )
-declare -r elements="vm simple-init devuser growroot openssh-server"
-declare -r one_distro=${1}
-declare -r BASE_PATH=$(dirname $(readlink -f $0) | sed "s@/xci/.*@@")
-
-if [[ -n ${one_distro} ]]; then
-       case ${one_distro} in
-               centos|ubuntu|opensuse) : ;;
-               *) echo "unsupported distribution"; exit 1 ;;
-       esac
-fi
-
-# devuser logins
-echo "Configuring devuser..."
-export DIB_DEV_USER_USERNAME=devuser
-export DIB_DEV_USER_PWDLESS_SUDO=1
-export DIB_DEV_USER_AUTHORIZED_KEYS=${BASE_PATH}/xci/scripts/vm/id_rsa_for_dib.pub
-export DIB_DEV_USER_PASSWORD=linux
-
-echo "Installing base dependencies..."
-sudo apt-get install -y -q=3 yum yum-utils rpm zypper kpartx python-pip debootstrap gnupg2
-
-echo "Installing diskimage-builder"
-
-sudo -H pip install -q diskimage-builder==2.9.0
-
-echo "Removing old files..."
-sudo rm -rf *.qcow2 *.sha256.txt
-
-do_build() {
-       local image=${1}-minimal
-       local image_name=${1}
-       echo "Building ${image}-${flavors[$image]}..."
-       export DIB_RELEASE=${flavors[$image]}
-       # Some defaults
-       export DIB_YUM_MINIMAL_CREATE_INTERFACES=1 # centos dhcp setup
-       disk-image-create --no-tmpfs -o ${image_name}.qcow2 ${elements} $image
-       sha256sum ${image_name}.qcow2 > ${image_name}.sha256.txt
-       echo "Done!"
-}
-
-if [[ -n ${one_distro} ]]; then
-       do_build ${one_distro}
-else
-       for image in "${!flavors[@]}"; do
-               image_name=${image/-minimal}
-               do_build $image_name
-       done
-fi
-
-exit 0
index 65133ed..8f2eff1 100755 (executable)
@@ -10,8 +10,6 @@
 
 set -e
 
-lsb_release -i | grep -q -i ubuntu || { echo "This script only works on Ubuntu distros"; exit 1; }
-
 export DEFAULT_XCI_TEST=${DEFAULT_XCI_TEST:-false}
 
 grep -q -i ^Y$ /sys/module/kvm_intel/parameters/nested || { echo "Nested virtualization is not enabled but it's needed for XCI to work"; exit 1; }
@@ -30,41 +28,86 @@ declare -r CPU=host
 declare -r NCPUS=24
 declare -r MEMORY=49152
 declare -r DISK=500
-declare -r NAME=${1}_xci_vm
+declare -r VM_NAME=${1}_xci_vm
 declare -r OS=${1}
 declare -r NETWORK="jenkins-test"
 declare -r BASE_PATH=$(dirname $(readlink -f $0) | sed "s@/xci/.*@@")
 
-echo "Preparing new virtual machine '${NAME}'..."
+echo "Preparing new virtual machine '${VM_NAME}'..."
+
+source /etc/os-release
+echo "Installing host (${ID,,}) dependencies..."
+# check we can run sudo
+if ! sudo -n "true"; then
+       echo ""
+       echo "passwordless sudo is needed for '$(id -nu)' user."
+       echo "Please fix your /etc/sudoers file. You likely want an"
+       echo "entry like the following one..."
+       echo ""
+       echo "$(id -nu) ALL=(ALL) NOPASSWD: ALL"
+       exit 1
+fi
+case ${ID,,} in
+       *suse) sudo zypper -q -n in virt-manager qemu-kvm qemu-tools libvirt-daemon docker libvirt-client libvirt-daemon-driver-qemu iptables ebtables dnsmasq
+                         ;;
+       centos) sudo yum install -q -y epel-release
+                       sudo yum install -q -y in virt-manager qemu-kvm qemu-kvm-tools qemu-img libvirt-daemon-kvm docker iptables ebtables dnsmasq
+                       ;;
+       ubuntu) sudo apt-get install -y -q=3 virt-manager qemu-kvm libvirt-bin qemu-utils docker.io docker iptables ebtables dnsmasq
+                       ;;
+esac
+
+echo "Ensuring libvirt and docker services are running..."
+sudo systemctl -q start libvirtd
+sudo systemctl -q start docker
+
+echo "Building new ${OS} image..."
 
-# NOTE(hwoarang) This should be removed when we move the dib images to a central place
 _retries=20
-echo "Building '${OS}' image (tail build.log for progress and failures)..."
-while [[ $_retries -ne 0 ]]; do
-       if pgrep build-dib-os.sh &>/dev/null; then
+while [[ $_retries -gt 0 ]]; do
+       if pgrep -a docker | grep -q docker-dib-xci &> /dev/null; then
                echo "There is another dib process running... ($_retries retries left)"
                sleep 60
                (( _retries = _retries - 1 ))
        else
-               if [[ -n ${JENKINS_HOME} ]]; then
-                       $BASE_PATH/xci/scripts/vm/build-dib-os.sh ${OS} 2>&1 | tee build.log
-               else
-                       $BASE_PATH/xci/scripts/vm/build-dib-os.sh ${OS} > build.log 2>&1
+               docker_cmd="sudo docker"
+               # See if we can run docker as regular user.
+               docker ps &> /dev/null && docker_cmd="docker"
+               docker_name="docker_xci_builder_${OS}"
+               # Destroy previous containers
+               if eval $docker_cmd ps -a | grep -q ${docker_name} &>/dev/null; then
+                       echo "Destroying previous container..."
+                       eval $docker_cmd rm -f ${docker_name}
                fi
+               # Prepare new working directory
+               dib_workdir="$(pwd)/docker_dib_xci_workdir"
+               [[ ! -d $dib_workdir ]] && mkdir $dib_workdir
+               chmod 777 -R $dib_workdir
+               uid=$(id -u)
+               gid=$(id -g)
+               # Get rid of stale files
+               rm -rf $dib_workdir/*.qcow2 $dib_workdir/*.sha256.txt $dib_workdir/*.d
+               echo "Getting the latest docker image..."
+               eval $docker_cmd pull hwoarang/docker-dib-xci:latest
+               echo "Initiating dib build..."
+               eval $docker_cmd run --name ${docker_name} \
+                       --rm --privileged=true -e ONE_DISTRO=${OS} \
+                       -t -v $dib_workdir:$dib_workdir -w $dib_workdir \
+                       hwoarang/docker-dib-xci '/usr/bin/do-build.sh'
+               sudo chown $uid:$gid $dib_workdir/${OS}.qcow2
+               declare -r OS_IMAGE_FILE=$dib_workdir/${OS}.qcow2
+
                break
        fi
 done
 
-[[ ! -e ${OS}.qcow2 ]] && echo "${OS}.qcow2 not found! This should never happen!" && exit 1
-
-sudo apt-get install -y -q=3 virt-manager qemu-kvm libvirt-bin qemu-utils
-sudo systemctl -q start libvirtd
+[[ ! -e ${OS_IMAGE_FILE} ]] && echo "${OS_IMAGE_FILE} not found! This should never happen!" && exit 1
 
 echo "Resizing disk image '${OS}' to ${DISK}G..."
-qemu-img resize ${OS}.qcow2 ${DISK}G
+qemu-img resize ${OS_IMAGE_FILE} ${DISK}G
 
 echo "Creating new network '${NETWORK}' if it does not exist already..."
-if ! sudo virsh net-list --name | grep -q ${NETWORK}; then
+if ! sudo virsh net-list --name --all | grep -q ${NETWORK}; then
        cat > /tmp/${NETWORK}.xml <<EOF
 <network>
   <name>${NETWORK}</name>
@@ -82,38 +125,39 @@ if ! sudo virsh net-list --name | grep -q ${NETWORK}; then
 </network>
 EOF
        sudo virsh net-define /tmp/${NETWORK}.xml
-       sudo virsh net-autostart ${NETWORK}
-       sudo virsh net-start ${NETWORK}
 fi
 
+sudo virsh net-list --autostart | grep -q ${NETWORK} || sudo virsh net-autostart ${NETWORK}
+sudo virsh net-list --inactive | grep -q ${NETWORK} && sudo virsh net-start ${NETWORK}
+
 echo "Destroying previous instances if necessary..."
-sudo virsh destroy ${NAME} || true
-sudo virsh undefine ${NAME} || true
+sudo virsh destroy ${VM_NAME} || true
+sudo virsh undefine ${VM_NAME} || true
 
-echo "Installing virtual machine '${NAME}'..."
-sudo virt-install -n ${NAME} --memory ${MEMORY} --vcpus ${NCPUS} --cpu ${CPU} \
-       --import --disk=${OS}.qcow2,cache=unsafe --network network=${NETWORK} \
+echo "Installing virtual machine '${VM_NAME}'..."
+sudo virt-install -n ${VM_NAME} --memory ${MEMORY} --vcpus ${NCPUS} --cpu ${CPU} \
+       --import --disk=${OS_IMAGE_FILE},cache=unsafe --network network=${NETWORK} \
        --graphics none --hvm --noautoconsole
 
 _retries=30
 while [[ $_retries -ne 0 ]]; do
-       _ip=$(sudo virsh domifaddr ${NAME} | grep -o --colour=never 192.168.140.[[:digit:]]* | cat )
+       _ip=$(sudo virsh domifaddr ${VM_NAME} | grep -o --colour=never 192.168.140.[[:digit:]]* | cat )
        if [[ -z ${_ip} ]]; then
-               echo "Waiting for '${NAME}' virtual machine to boot ($_retries retries left)..."
+               echo "Waiting for '${VM_NAME}' virtual machine to boot ($_retries retries left)..."
                sleep 5
                (( _retries = _retries - 1 ))
        else
                break
        fi
 done
-[[ -n $_ip ]] && echo "'${NAME}' virtual machine is online at $_ip"
-[[ -z $_ip ]] && echo "'${NAME}' virtual machine did not boot on time" && exit 1
+[[ -n $_ip ]] && echo "'${VM_NAME}' virtual machine is online at $_ip"
+[[ -z $_ip ]] && echo "'${VM_NAME}' virtual machine did not boot on time" && exit 1
 
 # Fix up perms if needed to make ssh happy
 chmod 600 ${BASE_PATH}/xci/scripts/vm/id_rsa_for_dib*
 # Remove it from known_hosts
 ssh-keygen -R $_ip || true
-ssh-keygen -R ${NAME} || true
+ssh-keygen -R ${VM_NAME} || true
 
 declare -r vm_ssh="ssh -o StrictHostKeyChecking=no -i ${BASE_PATH}/xci/scripts/vm/id_rsa_for_dib -l devuser"
 
@@ -131,13 +175,13 @@ while [[ $_retries -ne 0 ]]; do
                (( _retries = _retries - 1 ))
        fi
 done
-[[ $_ssh_exit != 0 ]] && echo "Failed to SSH to the virtual machine '${NAME}'! This should never happen!" && exit 1
+[[ $_ssh_exit != 0 ]] && echo "Failed to SSH to the virtual machine '${VM_NAME}'! This should never happen!" && exit 1
 
-echo "Congratulations! Your shiny new '${NAME}' virtual machine is fully operational! Enjoy!"
+echo "Congratulations! Your shiny new '${VM_NAME}' virtual machine is fully operational! Enjoy!"
 
-echo "Adding ${NAME}_xci_vm entry to /etc/hosts"
-sudo sed -i "/.*${NAME}.*/d" /etc/hosts
-sudo bash -c "echo '${_ip} ${NAME}' >> /etc/hosts"
+echo "Adding ${VM_NAME}_xci_vm entry to /etc/hosts"
+sudo sed -i "/.*${VM_NAME}.*/d" /etc/hosts
+sudo bash -c "echo '${_ip} ${VM_NAME}' >> /etc/hosts"
 
 echo "Dropping a minimal .ssh/config file"
 cat > $HOME/.ssh/config<<EOF
@@ -157,24 +201,26 @@ EOF
 
 echo "Preparing test environment..."
 # *_xci_vm hostname is invalid. Letst just use distro name
-$vm_ssh $_ip "sudo hostname ${NAME/_xci*}"
+$vm_ssh $_ip "sudo hostname ${VM_NAME/_xci*}"
 # Start with good dns
 $vm_ssh $_ip 'sudo bash -c "echo nameserver 8.8.8.8 > /etc/resolv.conf"'
 $vm_ssh $_ip 'sudo bash -c "echo nameserver 8.8.4.4 >> /etc/resolv.conf"'
 cat > ${BASE_PATH}/vm_hosts.txt <<EOF
-127.0.0.1 localhost ${NAME/_xci*}
+127.0.0.1 localhost ${VM_NAME/_xci*}
 ::1 localhost ipv6-localhost ipv6-loopback
 fe00::0 ipv6-localnet
 fe00::1 ipv6-allnodes
 fe00::2 ipv6-allrouters
 ff00::3 ipv6-allhosts
-$_ip ${NAME/_xci*}
+$_ip ${VM_NAME/_xci*}
 EOF
 
 # Need to copy releng-xci to the vm so we can execute stuff
 do_copy() {
        rsync -a \
-               --exclude "${NAME}*" \
+               --exclude "${VM_NAME}*" \
+               --exclude "${OS}*" \
+               --exclude "$dib_workdir*" \
                --exclude "build.log" \
                -e "$vm_ssh" ${BASE_PATH}/* $_ip:~/releng-xci/
 }