commit 4b357bee36388bb3381cd349623c21b5c299aede Author: Dustin C. Hatch Date: Sun Sep 22 11:44:48 2013 -0500 create-vmachine: Initial commit diff --git a/create-vmachine.sh b/create-vmachine.sh new file mode 100755 index 0000000..755ab1f --- /dev/null +++ b/create-vmachine.sh @@ -0,0 +1,162 @@ +#!/bin/bash +# Creates a new virtual machine from the given stage3 tarball + +DOMNAME="$1" +STAGE_TBZ="$2" +VMNAME=$(echo "${DOMNAME}" | tr '[:upper:]' '[:lower:]') +VM_FQDN="${VMNAME}.$(hostname -d)" + +VG=vmachines +POOL=LVM +DOMXML_TMPL=/etc/libvirt/qemu/_template.xml +MOUNTPOINT=/mnt/new_vmachine +PUPPETMASTER=$(hostname -f) +PORTAGE_PROFILE="default/linux/amd64/13.0" + +PORTDIR=$(portageq envvar PORTDIR) +DISTDIR=$(portageq envvar DISTDIR) +PKGDIR=$(portageq envvar PKGDIR) + +if [[ -z $STAGE_TBZ || -z $VMNAME ]]; then + echo "Usage: $(basename $0) " >&2 + exit 1 +fi + +set -e + +if lvdisplay ${VG}/${VMNAME} >/dev/null 2>&1; then + echo "ERROR: Logical volume ${VMNAME} already exists in group ${VG}" >&2 + exit 2 +fi + +echo "Creating storage volume..." +virsh -c qemu:///system vol-create-as ${POOL} ${VMNAME} 2G + +echo "Creating LVM volumes..." +pvcreate /dev/${VG}/${VMNAME} +vgcreate ${VMNAME} /dev/${VG}/${VMNAME} +lvcreate -nroot -L100M ${VMNAME} +lvcreate -nhome -L200M ${VMNAME} +lvcreate -nvar -L400M ${VMNAME} +lvcreate -nusr -l100%FREE ${VMNAME} + +echo "Creating XFS filesystems..." +for fs in root home usr var; do + mkfs.xfs -L$fs -q /dev/${VMNAME}/$fs +done + +echo "Mounting filesystems..." +[[ ! -d "${MOUNTPOINT}" ]] && mkdir -p "${MOUNTPOINT}" +mount /dev/${VMNAME}/root "${MOUNTPOINT}" +for fs in home usr var; do + mkdir "${MOUNTPOINT}"/$fs + mount /dev/${VMNAME}/$fs "${MOUNTPOINT}"/$fs +done +mkdir "${MOUNTPOINT}"/run +mount -t tmpfs tmpfs "${MOUNTPOINT}"/run + +echo "Extracting stage tarball..." +tar -xjpf "${STAGE_TBZ}" -C "${MOUNTPOINT}" + +echo "Installing critical packages..." +# Installing packages must be done in a chroot instead of using the $ROOT +# Portage environment variable because several ebuilds use enewuser/enewgroup +# to create system users, which creates the user on the host system, not the +# target system. See Gentoo bug #53269 for details on the problem. + +mkdir "${MOUNTPOINT}"/usr/portage +mount -obind "${PORTDIR}" "${MOUNTPOINT}"/usr/portage +mount -obind "${DISTDIR}" "${MOUNTPOINT}"/usr/portage/distfiles +mount -obind "${PKGDIR}" "${MOUNTPOINT}"/usr/portage/packages +mount -t tmpfs tmpfs "${MOUNTPOINT}"/tmp +mount -t proc proc "${MOUNTPOINT}"/proc +mount -t sysfs sysfs "${MOUNTPOINT}"/sys + +cat < "${MOUNTPOINT}"/build-base.sh +#!/bin/bash + +set -e + +export EMERGE_DEFAULT_OPTS="--binpkg-respect-use=y" +export FEATURES="-news" + +env-update +USE=-thin emerge -jkv xfsprogs nfs-utils lvm2 +rc-update add lvm boot +EOF +chmod u+x "${MOUNTPOINT}"/build-base.sh +chroot "${MOUNTPOINT}" /build-base.sh +rm "${MOUNTPOINT}"/build-base.sh + +echo "Installing Puppet..." +cat < "${MOUNTPOINT}"/build-puppet.sh +#!/bin/bash + +set -e + +export EMERGE_DEFAULT_OPTS="--binpkg-respect-use=y" +export FEATURES="-news" + +RUBY_TARGETS=ruby18 USE="-gdbm minimal old-output" emerge -jkv puppet +rc-update add puppet default +EOF +chmod u+x "${MOUNTPOINT}"/build-puppet.sh +chroot "${MOUNTPOINT}" /build-puppet.sh +rm "${MOUNTPOINT}"/build-puppet.sh + +echo "Configuring Puppet..." +cfg_head=$(mktemp) +cfg_foot=$(mktemp) +awk '/\[agent\]/ {exit} {print}' "${MOUNTPOINT}"/etc/puppet/puppet.conf > ${cfg_head} +awk '/\[agent\]/,0' "${MOUNTPOINT}"/etc/puppet/puppet.conf > ${cfg_foot} +cat ${cfg_head} > "${MOUNTPOINT}"/etc/puppet/puppet.conf +cat <> "${MOUNTPOINT}"/etc/puppet/puppet.conf + server = ${PUPPETMASTER} + pluginsync = true + +EOF +cat ${cfg_foot} >> "${MOUNTPOINT}"/etc/puppet/puppet.conf +rm ${cfg_head} ${cfg_foot} + +echo "Setting hostname..." +sed -i "s/localhost/${VMNAME}/" "${MOUNTPOINT}"/etc/conf.d/hostname + +echo "Configuring network..." +echo 'config_eth0="dhcp"' > "${MOUNTPOINT}"/etc/conf.d/net +echo 'dhcpcd_eth0="-q"' >> "${MOUNTPOINT}"/etc/conf.d/net +ln -s net.lo "${MOUNTPOINT}"/etc/init.d/net.eth0 +ln -s /etc/init.d/net.eth0 "${MOUNTPOINT}"/etc/runlevels/default/ +ln -s /etc/init.d/sshd "${MOUNTPOINT}"/etc/runlevels/default/ + +echo "Configuring fstab..." +cat << EOF > "${MOUNTPOINT}"/etc/fstab +LABEL=root / xfs noatime 0 1 +LABEL=usr /usr xfs noatime 0 2 +LABEL=var /var xfs noatime 0 2 +LABEL=home /home xfs noatime 0 2 +tmpfs /tmp tmpfs defaults 0 0 +EOF + +echo "Creating read-only root filesystem compatibility symlinks..." +rm -f "${MOUNTPOINT}"/etc/{resolv,ntp}.conf +rm -f "${MOUNTPOINT}"/etc/mtab +ln -s /proc/mounts "${MOUNTPOINT}"/etc/mtab +ln -s /run/resolv.conf "${MOUNTPOINT}"/etc/resolv.conf +ln -s /run/ntp.conf "${MOUNTPOINT}"/etc/ntp.conf + +echo "Blanking root password..." +sed -i 's/^root:.*/root::0:0:::::/' "${MOUNTPOINT}"/etc/shadow + +echo "Enabling serial console..." +sed -i 's/#s0/s0/' "${MOUNTPOINT}"/etc/inittab + +echo "Cleaning up..." +umount "${MOUNTPOINT}"/usr/portage/{packages,distfiles,} +rmdir "${MOUNTPOINT}"/usr/portage +umount "${MOUNTPOINT}"/{tmp,proc,sys,run,usr,var,home,} +vgchange -an ${VMNAME} + +echo "Creating libvirt domain..." +m4 -P -DNAME="${DOMNAME}" "${DOMXML_TMPL}" | virsh -c qemu:///system define /dev/stdin +echo "Starting virtual machine..." +virsh -c qemu:///system start ${DOMNAME}