diff --git a/20140204.nue1.buildimage/.gitignore b/20140204.nue1.buildimage/.gitignore new file mode 100644 index 0000000..9603193 --- /dev/null +++ b/20140204.nue1.buildimage/.gitignore @@ -0,0 +1,5 @@ +.vagrant +*.bz2 +*.qcow2 +*.tmp +authorized_keys diff --git a/20140204.nue1.buildimage/Makefile b/20140204.nue1.buildimage/Makefile new file mode 100644 index 0000000..5a6fab5 --- /dev/null +++ b/20140204.nue1.buildimage/Makefile @@ -0,0 +1,24 @@ +YYYYMMDD := $(shell date +%Y%m%d) + +default: gen + +clean: + rm -f *.bz2 *.qcow2 *.tmp authorized_keys + +setup: clean + ./detect-mirror.sh > ubuntu-mirror.tmp + cp $(HOME)/.ssh/id_rsa.pub ./authorized_keys + +gen: setup + ./gen.sh + +upload: + rsync -avzP ./*.qcow2 \ + $(KVM_REMOTE_HOST):/storage/images/ + +sync: clean + rsync -avP \ + --exclude=/.git \ + --exclude=/.vagrant \ + ./ \ + $(KVM_REMOTE_HOST):/storage/buildimage/ diff --git a/20140204.nue1.buildimage/README.md b/20140204.nue1.buildimage/README.md new file mode 100644 index 0000000..835b52f --- /dev/null +++ b/20140204.nue1.buildimage/README.md @@ -0,0 +1,53 @@ +# KVM Ubuntu Image Builder + +This is a Vagrant-based qcow2 image builder to build root images for +KVM/qemu. + +Supports: + +* Ubuntu 12.04 precise amd64 +* Ubuntu 13.10 saucy amd64 + +# Assumptions + +This will use whatever `~/.ssh/id_rsa.pub` is found on the host build system +as the `/root/.ssh/authorized_keys` inside the image being built. + +The root password is set to 'root', but ssh password logins are disabled, so +it only works at the console. + +The mirror in the image is set to `http://mirror.localservice/ubuntu`. It +is expected that the VM environment you are using will make this resolve +appropriately and point at a local reverse proxy or full mirror. + +# Requires + +## Common + +* curl +* jq + +## OSX + +* Vagrant + +## Linux + +* root +* kpartx +* debootstrap +* lvm2 +* qemu-utils + +# todo + +* support 12.04 (precise) or 12.10 (quantal) (chef server!) +* refactor local modifications/packages out of base build + +# local changes todo + +* remove whoopsie +* remove libwhoopsie0 +* remove popcon / popularity-contest +* remove landscape stuff +* switch ssh to systemd invoked service diff --git a/20140204.nue1.buildimage/Vagrantfile b/20140204.nue1.buildimage/Vagrantfile new file mode 100644 index 0000000..56254ee --- /dev/null +++ b/20140204.nue1.buildimage/Vagrantfile @@ -0,0 +1,73 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" + +SETUP_BASE = <<-EOF +#!/bin/bash +set -e + +# byobu lags login in this vm for some reason? +test -e /etc/profile.d/Z97-byobu.sh && rm /etc/profile.d/Z97-byobu.sh + +echo "UseDNS no" >> /etc/ssh/sshd_config +service ssh restart + +echo "exec sudo -i" >> /home/vagrant/.bashrc + +function set_apt_mirror () { + CN="$(lsb_release -c -s)" + RPS="main restricted multiverse universe" + echo "deb $1 $CN $RPS" > /etc/apt/sources.list.new + for P in updates backports security ; do + echo "deb $1 $CN-$P $RPS" >> /etc/apt/sources.list.new + done + mv /etc/apt/sources.list.new /etc/apt/sources.list +} + +export UBUNTU_MIRROR_URL="`cat /vagrant/ubuntu-mirror.tmp`" + +if [[ ! -z "$UBUNTU_MIRROR_URL" ]]; then + set_apt_mirror "$UBUNTU_MIRROR_URL" +fi + +if [[ "$(lsb_release -s -c)" == "saucy" ]]; then + dpkg --remove-architecture i386 +else + rm /etc/dpkg/dpkg.cfg.d/multiarch +fi +apt-get update +apt-get -y install kpartx debootstrap lvm2 qemu-utils + +DISTS="precise saucy" + +for DIST in $DISTS; do + export KEYFILE="/vagrant/authorized_keys" + /vagrant/buildimage.sh $DIST || exit $? + mv /tmp/*64.qcow2 /vagrant/ + exit 0 # FIXME +done + +EOF + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + config.vm.box = "ubuntu-12.04" + config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/precise/" + \ + "current/precise-server-cloudimg-amd64-vagrant-disk1.box" + config.cache.auto_detect = true if Vagrant.has_plugin?("vagrant-cachier") + + # bridge to my actual local lan instead of the private vagrant + # network so that avahi discover will work right to find my mirror + # osx requires it to be the full descriptive name, mine is e.g. + # "en4: Display Ethernet" (tb display wired ethernet) + if ENV['VAGRANT_BRIDGE_DEVICE'] + config.vm.network "public_network", + :bridge => ENV['VAGRANT_BRIDGE_DEVICE'] + end + + config.vm.provision "shell", inline: SETUP_BASE + config.vm.provider :virtualbox do |vb| + vb.customize ["modifyvm", :id, "--memory", "2048"] + end +end diff --git a/20140204.nue1.buildimage/buildimage.sh b/20140204.nue1.buildimage/buildimage.sh new file mode 100755 index 0000000..549578e --- /dev/null +++ b/20140204.nue1.buildimage/buildimage.sh @@ -0,0 +1,385 @@ +#!/bin/bash +set -e +set -v +set -x + +SAVESPACE=1 +WITHCHEF=1 +ORGNAME="eeqj" +DSIZE="25G" # disk size + +# releases we support right now +SUPPORTED="precise saucy" + +if [[ $# -ne 1 ]]; then + echo "usage: $0 " > /dev/stderr + echo "supported ubuntu releases: $SUPPORTED" > /dev/stderr + exit 127 +fi +R="$1" # release +if ! [[ "$SUPPORTED" =~ "$R" ]] ; then + echo "$0: unsupported ubuntu release $R, sorry." > /dev/stderr + exit 127 +fi + +MR="/tmp/kvmbuild-${R}" +RI="/tmp/kvmbuild-${R}.img" # raw image +VGN="vmvg0" # volume group name +DATE="$(date -u +%Y%m%d)" +LONGDATE="$(date -u +%Y-%m-%dT%H:%M:%S%z)" +LOOPDEV="$(losetup -f)" +LDBASE="$(basename $LOOPDEV)" +ROOTPW="root" + +if [[ -e /dev/$VGN ]]; then + echo "$0: error, vg $VGN already exists" > /dev/stderr + exit 127 +fi + +if [[ -e "$MR" ]]; then + echo "$0: error, chroot dir $MR already exists" > /dev/stderr + exit 127 +fi + +if [[ -e "$RI" ]]; then + echo "$0: error, intermediate image file $RI already exists" > /dev/stderr + exit 127 +fi + +function detect_local_mirror () { + TF="${UBUNTU_MIRROR_URL}/dists/${R}/Release" + MOK="$(curl -m 1 --head ${TF} 2>&1 | grep '200 OK' | wc -l)" + if [ $MOK -gt 0 ]; then + echo "$UBUNTU_MIRROR_URL" + else + echo "http://archive.ubuntu.com/ubuntu/" + fi +} + +UM="$(detect_local_mirror)" + +# create sparse file and partition it +dd if=/dev/zero of=$RI bs=1 count=0 seek=$DSIZE +parted -s $RI mklabel msdos +parted -a optimal $RI mkpart primary 0% 200MiB +parted -a optimal $RI mkpart primary 200MiB 100% +parted $RI set 1 boot on +losetup $LOOPDEV $RI +kpartx -av $LOOPDEV +BOOTPARTLOOP="$(losetup -f)" +losetup $BOOTPARTLOOP /dev/mapper/${LDBASE}p1 + +# make boot filesystem: +if [[ "$R" == "saucy" ]]; then + FSTYPE="ext4" +else + FSTYPE="ext3" +fi + +mkfs.${FSTYPE} -L BOOT $BOOTPARTLOOP +tune2fs -c -1 $BOOTPARTLOOP + +# create root vg and filesystem: +pvcreate /dev/mapper/${LDBASE}p2 +vgcreate $VGN /dev/mapper/${LDBASE}p2 +lvcreate -l 100%FREE -n root $VGN +mkfs.${FSTYPE} -L ROOT /dev/$VGN/root + +# mount stuff +mkdir -p $MR +MR="$(readlink -f $MR)" +mount /dev/$VGN/root $MR +mkdir $MR/boot +mount $BOOTPARTLOOP $MR/boot + +# install base: +echo "*** installing base $R system from $UM..." +debootstrap --arch amd64 $R $MR $UM + +# temporary config for install: +RPS="main restricted multiverse universe" +echo "deb $UM $R $RPS" > $MR/etc/apt/sources.list +for P in updates backports security ; do + echo "deb $UM $R-$P $RPS" >> $MR/etc/apt/sources.list +done + +# disable apt installation exuberance +cat > $MR/etc/apt/apt.conf.d/99-vm-no-extras-please < $MR/etc/environment </dev/null' | chroot $MR + +BUUID="$(blkid -s UUID -o value $BOOTPARTLOOP)" +RUUID="$(blkid -s UUID -o value /dev/${VGN}/root)" + +# this has to come before packages: +cat > $MR/etc/fstab < $MR/etc/network/interfaces < $MR/etc/hosts < $MR/usr/sbin/policy-rc.d < /etc/ntp.conf.new +mv /etc/ntp.conf.new /etc/ntp.conf +EOF + +# tell ntp not to try to sync to anything +# if an ntp server comes from the dhcp server then it will use that +cat >> $MR/etc/ntp.conf <> $MR/etc/default/grub +# FIXME i think this is bogus, test changing it +echo "GRUB_SERIAL_COMMAND=\"serial --unit=0 --speed=9600 --stop=1\"" \ + >> $MR/etc/default/grub +if [[ "$R" == "saucy" ]]; then + echo "GRUB_TERMINAL=\"serial\"" >> $MR/etc/default/grub +fi +echo "GRUB_GFXPAYLOAD=\"text\"" >> $MR/etc/default/grub + +# set root password (only useful at console, ssh password login is disabled) +chroot $MR /bin/bash -c "echo \"root:$ROOTPW\" | chpasswd" + +chroot $MR grub-mkconfig -o /boot/grub/grub.cfg 2> /dev/null +cat > $MR/boot/grub/device.map < /dev/null + +# get rid of temporary device.map after grub is installed +rm $MR/boot/grub/device.map + +# remove initramfs entirely: +chroot $MR update-initramfs -d -k all + +# for some stupid reason, -k all doesn't work on gen after removing: +KERN="$(cd $MR/boot && ls vmlinuz*)" +VER="${KERN#vmlinuz-}" +chroot $MR update-initramfs -c -k $VER + +# start a getty on the serial port for kvm console login +if [[ "$R" == "saucy" ]]; then +cat > $MR/etc/init/ttyS0.conf < $MR/etc/dhcp/dhclient-exit-hooks.d/hostname <> $MR/etc/ssh/sshd_config +# in case dns is broken, don't lag logins +echo "UseDNS no" >> $MR/etc/ssh/sshd_config + +# clean apt cache +rm $MR/var/cache/apt/archives/*.deb + +# set dist apt source: +RPS="main restricted multiverse universe" +MURL="http://archive.ubuntu.com/ubuntu" +echo "deb $MURL $R $RPS" > $MR/etc/apt/sources.list +for P in updates backports security ; do + echo "deb $MURL $R-$P $RPS" >> $MR/etc/apt/sources.list +done + +# remove instance ssh host keys +rm $MR/etc/ssh/*key* +rm $MR/var/lib/dhcp/*.leases + +# remove temporary resolver, dhcp will fix it: +rm $MR/etc/resolv.conf + +# if there is an /etc/hostname then it won't +# pick up the right hostname from dhcp +test -e $MR/etc/hostname || rm $MR/etc/hostname + +mkdir $MR/lib/eeqjvmtools + +cat > $MR/lib/eeqjvmtools/expandroot.sh < $MR/etc/rc.local < /dev/null + done + for LODEV in /dev/mapper/loop*p1 ; do + S=${LODEV#/dev/mapper/} + S=${S%p1} + kpartx -dv /dev/$S + losetup -d /dev/$S + unset S + done + for LODEV in /dev/loop* ; do + losetup -d $LODEV 2> /dev/null + done + rm "$IM" + rmdir "$BD" + exit 127 + fi + mv /tmp/*${CN}64.qcow2 $OLDPWD + done + exit 0 +fi