From 28bb421156ea6a5b89957c224b6ab41d29789630 Mon Sep 17 00:00:00 2001 From: devrandom Date: Sat, 21 Apr 2012 22:44:00 -0700 Subject: [PATCH] First pass lxc support --- README.md | 15 ++++++++++- bin/gbuild | 22 ++++++++++++---- bin/make-base-vm | 41 ++++++++++++++++++++--------- etc/lxc.config.in | 32 +++++++++++++++++++++++ libexec/config-lxc | 4 +++ libexec/copy-from-target | 7 ++++- libexec/copy-to-target | 7 ++++- libexec/make-clean-vm | 53 ++++++++++++++++++++++++++++++++++++++ libexec/on-target | 11 +++++++- libexec/start-target | 13 ++++++---- libexec/stop-target | 20 ++++++++------ target-bin/bootstrap-fixup | 2 +- 12 files changed, 192 insertions(+), 35 deletions(-) create mode 100644 etc/lxc.config.in create mode 100755 libexec/config-lxc create mode 100755 libexec/make-clean-vm diff --git a/README.md b/README.md index e782ca0..5028a02 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,30 @@ This performs a build inside a VM, with deterministic inputs and outputs. If th Install prereqs: - sudo apt-get install python-vm-builder qemu-kvm apt-cacher + sudo apt-get install apt-cacher sudo service apt-cacher start +If you want to use kvm: + sudo apt-get install python-vm-builder qemu-kvm + +or alternatively, lxc (no need for hardware support): + sudo apt-get install debootstrap lxc + Create the base VM for use in further builds (requires sudo, please review the script): bin/make-base-vm + bin/make-base-vm --arch i386 + +or for lxc: + + bin/make-base-vm --lxc + bin/make-base-vm --lxc --arch i386 Copy any additional build inputs into a directory named _inputs_. Then execute the build using a YAML description file (can be run as non-root): + export USE_LXC=1 # LXC only bin/gbuild .yml or if you need to specify a commit for one of the git remotes: diff --git a/bin/gbuild b/bin/gbuild index 4516b6c..a59239d 100755 --- a/bin/gbuild +++ b/bin/gbuild @@ -22,7 +22,7 @@ def sanitize(str, where) end def sanitize_path(str, where) - raise "unsanitary string in #{where}" if (str =~ /[^\w\/.-]/) + raise "unsanitary string in #{where}" if (str =~ /[^\w\/.:-]/) str end @@ -34,6 +34,12 @@ def build_one_configuration(suite, arch, build_desc, reference_datetime) FileUtils.rm_f("var/build.log") bits = @bitness[arch] or raise "unknown architecture ${arch}" + + if ENV["USE_LXC"] + ENV["LXC_ARCH"] = arch + ENV["LXC_SUITE"] = suite + end + suitearch = "#{suite}-#{arch}" info "Stopping target if it is up" @@ -43,7 +49,7 @@ def build_one_configuration(suite, arch, build_desc, reference_datetime) unless @options[:skip_image] info "Making a new image copy" - system! "cp base-#{suitearch}.qcow2 target-#{suitearch}.qcow2" + system! "make-clean-vm --suite #{suite} --arch #{arch}" end info "Starting target" @@ -66,7 +72,7 @@ def build_one_configuration(suite, arch, build_desc, reference_datetime) build_desc["files"].each do |filename| filename = sanitize(filename, "files section") - system! "cd inputs && copy-to-target #{@quiet_flag} #{filename} build/" + system! "copy-to-target #{@quiet_flag} inputs/#{filename} build/" end info "Updating apt-get repository (log in var/install.log)" @@ -92,8 +98,14 @@ def build_one_configuration(suite, arch, build_desc, reference_datetime) script.puts "REFERENCE_TIME='#{ref_time}'" script.puts build_desc["remotes"].each do |remote| - script.puts "git clone -q #{remote["url"]} build/#{remote["dir"]}" - script.puts "(cd build/#{remote["dir"]} && git checkout -q #{remote["commit"]})" + dir = sanitize(remote["dir"], remote["dir"]) + if File.exist?("inputs/#{dir}") + system!("cd inputs/#{dir} && git fetch") + else + system!("git clone -q #{sanitize_path(remote["url"], remote["url"])} inputs/#{dir}") + end + system! "copy-to-target #{@quiet_flag} inputs/#{dir} build/" + script.puts "(cd build/#{dir} && git checkout -q #{remote["commit"]})" end script.puts "cd build" script.puts build_desc["script"] diff --git a/bin/make-base-vm b/bin/make-base-vm index 11a75fe..3a67461 100755 --- a/bin/make-base-vm +++ b/bin/make-base-vm @@ -5,6 +5,7 @@ SUITE=lucid ARCH=amd64 MIRROR=http://${MIRROR_HOST:-127.0.0.1}:3142/archive.ubuntu.com/ubuntu SECURITY_MIRROR=http://${MIRROR_HOST:-127.0.0.1}:3142/security.ubuntu.com/ubuntu +LXC=0 usage() { echo "Usage: ${0##*/} [OPTION]..." @@ -12,8 +13,9 @@ usage() { echo cat << EOF --help display this help and exit - --suite=U build suite U instead of lucid - --arch=A build architecture A (e.g. i386) instead of amd64 + --suite U build suite U instead of lucid + --arch A build architecture A (e.g. i386) instead of amd64 + --lxc use lxc instead of kvm The MIRROR_HOST environment variable can be used to change the apt-cacher host. It should be something that the target VM can @@ -38,6 +40,10 @@ if [ $# != 0 ] ; then ARCH="$2" shift 2 ;; + --lxc) + LXC=1 + shift 1 + ;; --*) echo "unrecognized option $1" exit 1 @@ -56,21 +62,32 @@ if [ ! -e var/id_dsa ]; then fi OUT=base-$SUITE-$ARCH -if [ -e $OUT.qcow2 ]; then - echo $OUT.qcow2 already exists, please remove it first - exit 1 -fi - -rm -rf $OUT - FLAVOUR=virtual if [ $ARCH = "amd64" -a $SUITE = "hardy" ]; then FLAVOUR=server fi -sudo vmbuilder kvm ubuntu --arch=$ARCH --suite=$SUITE --addpkg=openssh-server,pciutils,build-essential,git-core,subversion --ssh-key=var/id_dsa.pub --ssh-user-key=var/id_dsa.pub --mirror=$MIRROR --security-mirror=$SECURITY_MIRROR --dest=$OUT --flavour=$FLAVOUR --firstboot=`pwd`/target-bin/bootstrap-fixup +addpkg=openssh-server,pciutils,build-essential,git-core,subversion -mv $OUT/*.qcow2 $OUT.qcow2 +if [ $LXC = "0" ]; then + if [ -e $OUT.qcow2 ]; then + echo $OUT.qcow2 already exists, please remove it first + exit 1 + fi + + rm -rf $OUT + sudo vmbuilder kvm ubuntu --arch=$ARCH --suite=$SUITE --addpkg=$addpkg --ssh-key=var/id_dsa.pub --ssh-user-key=var/id_dsa.pub --mirror=$MIRROR --security-mirror=$SECURITY_MIRROR --dest=$OUT --flavour=$FLAVOUR --firstboot=`pwd`/target-bin/bootstrap-fixup + mv $OUT/*.qcow2 $OUT.qcow2 + rm -rf $OUT +else + if [ -e $OUT ]; then + echo $OUT already exists, please remove it first + exit 1 + fi + + rm -rf $OUT-root + sudo debootstrap --include=$addpkg --arch=$ARCH $SUITE $OUT-root $MIRROR + sudo target-bin/bootstrap-fixup $OUT-root +fi -rm -rf $OUT diff --git a/etc/lxc.config.in b/etc/lxc.config.in new file mode 100644 index 0000000..b4c02e5 --- /dev/null +++ b/etc/lxc.config.in @@ -0,0 +1,32 @@ +lxc.tty = 4 +lxc.pts = 1024 +lxc.rootfs = ROOTFS +lxc.arch = ARCH +lxc.cgroup.devices.deny = a +# /dev/null and zero +lxc.cgroup.devices.allow = c 1:3 rwm +lxc.cgroup.devices.allow = c 1:5 rwm +# consoles +lxc.cgroup.devices.allow = c 5:1 rwm +lxc.cgroup.devices.allow = c 5:0 rwm +lxc.cgroup.devices.allow = c 4:0 rwm +lxc.cgroup.devices.allow = c 4:1 rwm +# /dev/{,u}random +lxc.cgroup.devices.allow = c 1:9 rwm +lxc.cgroup.devices.allow = c 1:8 rwm +lxc.cgroup.devices.allow = c 136:* rwm +lxc.cgroup.devices.allow = c 5:2 rwm +# rtc +lxc.cgroup.devices.allow = c 254:0 rwm + +# mounts points +lxc.mount.entry=proc ROOTFS/proc proc nodev,noexec,nosuid 0 0 +lxc.mount.entry=sysfs ROOTFS/sys sysfs defaults 0 0 + +# Container with network virtualized using a pre-configured bridge named br0 and +# veth pair virtual network devices +# On the host, run: ifconfig br0 up 10.0.2.2 +lxc.network.type = veth +lxc.network.flags = up +lxc.network.link = br0 +lxc.network.ipv4 = 10.0.2.5/24 diff --git a/libexec/config-lxc b/libexec/config-lxc new file mode 100755 index 0000000..1a2ed94 --- /dev/null +++ b/libexec/config-lxc @@ -0,0 +1,4 @@ +#!/bin/bash + +wd=`pwd` +sed "s;ROOTFS;$wd/target-$LXC_SUITE-$LXC_ARCH-root;;s;ARCH;$LXC_ARCH;g" < etc/lxc.config.in > var/lxc.config diff --git a/libexec/copy-from-target b/libexec/copy-from-target index e094ee4..85869be 100755 --- a/libexec/copy-from-target +++ b/libexec/copy-from-target @@ -46,4 +46,9 @@ if [ $# = 0 ] ; then exit 1 fi -scp $QUIET_FLAG -oConnectTimeout=5 -oNoHostAuthenticationForLocalhost=yes -i ${GITIAN_BASE:-.}/var/id_dsa -P $VM_SSH_PORT -r $TUSER@localhost:$1 $2 +if [ -z "$USE_LXC" ]; then + scp $QUIET_FLAG -oConnectTimeout=5 -oNoHostAuthenticationForLocalhost=yes -i ${GITIAN_BASE:-.}/var/id_dsa -P $VM_SSH_PORT -r $TUSER@localhost:$1 $2 +else + config-lxc + sudo lxc-start -n gitian -f var/lxc.config -- sudo -i -u $TUSER tar -cf - "$1" | tar -C "$2" -xkf - +fi diff --git a/libexec/copy-to-target b/libexec/copy-to-target index 917d92a..93d64d0 100755 --- a/libexec/copy-to-target +++ b/libexec/copy-to-target @@ -46,4 +46,9 @@ if [ $# = 0 ] ; then exit 1 fi -scp $QUIET_FLAG -oConnectTimeout=5 -oNoHostAuthenticationForLocalhost=yes -i ${GITIAN_BASE:-.}/var/id_dsa -P $VM_SSH_PORT $1 $TUSER@localhost:$2 +if [ -z "$USE_LXC" ]; then + scp $QUIET_FLAG -oConnectTimeout=5 -oNoHostAuthenticationForLocalhost=yes -i ${GITIAN_BASE:-.}/var/id_dsa -P $VM_SSH_PORT $1 $TUSER@localhost:$2 +else + config-lxc + tar -C `dirname "$1"` -cf - `basename "$1"` | sudo lxc-start -n gitian -f var/lxc.config -- sudo -i -u $TUSER tar -C "$2" -xf - +fi diff --git a/libexec/make-clean-vm b/libexec/make-clean-vm new file mode 100755 index 0000000..5c66a27 --- /dev/null +++ b/libexec/make-clean-vm @@ -0,0 +1,53 @@ +#!/bin/sh +set -e + +SUITE=lucid +ARCH=amd64 + +usage() { + echo "Usage: ${0##*/} [OPTION]..." + echo "Make a clean copy of the base client." + echo + cat << EOF + --help display this help and exit + --suite U build suite U instead of lucid + --arch A build architecture A (e.g. i386) instead of amd64 +EOF +} + +if [ $# != 0 ] ; then + while true ; do + case "$1" in + --help|-h) + usage + exit 0 + ;; + --suite|-s) + SUITE="$2" + shift 2 + ;; + --arch|-a) + ARCH="$2" + shift 2 + ;; + --*) + echo "unrecognized option $1" + exit 1 + ;; + *) + break + ;; + esac + done +fi + +BASE=base-$SUITE-$ARCH-root +OUT=target-$SUITE-$ARCH-root + +if [ -z "$USE_LXC" ]; then + cp $BASE.qcow2 $OUT.qcow2 +else + sudo rm -rf $OUT + sudo cp -a $BASE $OUT + on-target -u root useradd -m ubuntu +fi diff --git a/libexec/on-target b/libexec/on-target index efd0653..8f1ceb4 100755 --- a/libexec/on-target +++ b/libexec/on-target @@ -41,4 +41,13 @@ fi # exit 1 #fi -ssh -oConnectTimeout=5 -oNoHostAuthenticationForLocalhost=yes -i ${GITIAN_BASE:-.}/var/id_dsa -p $VM_SSH_PORT $TUSER@localhost $* +if [ -z "$USE_LXC" ]; then + ssh -oConnectTimeout=5 -oNoHostAuthenticationForLocalhost=yes -i ${GITIAN_BASE:-.}/var/id_dsa -p $VM_SSH_PORT $TUSER@localhost $* +else + config-lxc + if [ $TUSER = "root" ]; then + sudo lxc-start -n gitian -f var/lxc.config -- $* + else + sudo lxc-start -n gitian -f var/lxc.config -- sudo -i -u $TUSER $* + fi +fi diff --git a/libexec/start-target b/libexec/start-target index 9ea3a01..e5e1976 100755 --- a/libexec/start-target +++ b/libexec/start-target @@ -5,8 +5,11 @@ ARCH=qemu$1 SUFFIX=$2 -kvm -cpu $ARCH -m ${VMEM:-2000} -smp ${NPROCS:-2} -drive file=target-$SUFFIX.qcow2 -net nic,model=virtio -net user,hostfwd=tcp:127.0.0.1:$VM_SSH_PORT-:22 -vnc 127.0.0.1:16 > var/target.log 2>&1 & - -echo $! > var/target.pid -wait -rm var/target.pid +if [ -z "$USE_LXC" ]; then + kvm -cpu $ARCH -m ${VMEM:-2000} -smp ${NPROCS:-2} -drive file=target-$SUFFIX.qcow2 -net nic,model=virtio -net user,hostfwd=tcp:127.0.0.1:$VM_SSH_PORT-:22 -vnc 127.0.0.1:16 > var/target.log 2>&1 & + echo $! > var/target.pid + wait + rm var/target.pid +else + true #sudo lxc-start -n gitian -c var/target.log -f lxc.config +fi diff --git a/libexec/stop-target b/libexec/stop-target index 425bc2c..003779c 100755 --- a/libexec/stop-target +++ b/libexec/stop-target @@ -1,14 +1,18 @@ #!/bin/sh -if [ ! -e var/target.pid ]; then exit; fi +if [ -z "$USE_LXC" ]; then + if [ ! -e var/target.pid ]; then exit; fi -on-target -u root halt -sleep 5 + on-target -u root halt + sleep 5 -if [ ! -e var/target.pid ]; then exit; fi -sleep 5 + if [ ! -e var/target.pid ]; then exit; fi + sleep 5 -if [ ! -e var/target.pid ]; then exit; fi + if [ ! -e var/target.pid ]; then exit; fi -echo Killing target since it did not shutdown within 10 seconds -kill `cat var/target.pid` + echo Killing target since it did not shutdown within 10 seconds + kill `cat var/target.pid` +else + true +fi diff --git a/target-bin/bootstrap-fixup b/target-bin/bootstrap-fixup index 9340f05..994c7ca 100755 --- a/target-bin/bootstrap-fixup +++ b/target-bin/bootstrap-fixup @@ -2,4 +2,4 @@ set -e -sed -i -e 's/127.0.0.1:/10.0.2.2:/' $1/etc/apt/sources.list +echo 'deb http://10.0.2.2:3142/archive.ubuntu.com/ubuntu lucid main universe' > $1/etc/apt/sources.list