summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvarac <varacanero@zeromail.org>2012-10-09 15:50:55 +0200
committervarac <varacanero@zeromail.org>2012-10-09 15:50:55 +0200
commit096642065e8e7398a957bebabbbc85b691bec3b4 (patch)
tree38f95cdf12e98ab4bd1e86d906777e205dc0eb63
initial commit, create-guest-with-cloudinit + helper scripts
-rwxr-xr-xcreate-guest-with-cloudinit92
-rwxr-xr-xlibvirt-make-seed-disk152
-rwxr-xr-xlibvirt-write-disk-attach-xml23
3 files changed, 267 insertions, 0 deletions
diff --git a/create-guest-with-cloudinit b/create-guest-with-cloudinit
new file mode 100755
index 0000000..56eec5f
--- /dev/null
+++ b/create-guest-with-cloudinit
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+VG='vg01'
+ETC='/etc/cloudinit'
+VARDIR='/var/lib/libvirt/cloudinit'
+
+fail() { [ $# -eq 0 ] || echo "$@"; exit 1; }
+bad_usage() { usage 1>&2; [ $# -eq 0 ] || fail "$@"; exit 1; }
+
+usage() {
+ cat <<EOF
+
+Usage: ${0##*/} [ $options ] guest_name
+
+ Creates a new guest VM using cloud-init to utilize nocloud.
+
+ options:
+ -h show usage
+ -s size disk size in GB
+
+EOF
+}
+
+
+short_opts="hs:"
+getopt_out=$(getopt --name "${0##*/}" \
+ --options "${short_opts}" -- "$@") &&
+ eval set -- "${getopt_out}" ||
+ fail "Error !"
+
+
+while [ $# -ne 0 ]; do
+ cur=${1}; next=${2};
+ case "$cur" in
+ -h) Usage ; exit 0;;
+ -s) size=$next; shift;;
+ --) shift; break;;
+ esac
+ shift;
+done
+
+
+[ $# -lt 1 ] && bad_usage "must provide guest name"
+[ $# -gt 1 ] && bad_usage "too many arguments"
+
+vmname=$1
+userdata="$ETC/$vmname-user-data"
+
+
+[ -e /dev/$VG/$vmname ] && fail "/dev/$VG/$vmname exists - please delete it or choose another guest name"
+
+[ -e $userdata ] || fail "please provide userdata in $userdata"
+
+echo
+echo "Creating guest VM $vmname with size: $size GB, using $userdata for clound-init"
+echo
+
+
+virsh dominfo $vmname > /dev/null 2>&1
+if [ $? -eq 0 ]; then fail "Domain $vmname is defined in libvirt. Please undefine first."; fi
+
+
+lvcreate -L ${size}g -n $vmname $VG
+virt-clone -o leap-baseimage-wheezy -n $vmname -f /dev/$VG/$vmname --force
+
+# resize second (root) partition
+echo ",+," | sfdisk -N2 /dev/$VG/$vmname > /dev/null
+
+libvirt-make-seed-disk $VARDIR/$vmname-user-data.img $userdata
+libvirt-write-disk-attach-xml $VARDIR/$vmname-user-data.img > $VARDIR/$vmname-disk-attach.xml
+
+echo
+echo "Attached userdata-disk is at $VARDIR/$vmname-user-data.img"
+echo
+echo "Finished creating guest $vmname. Enjoy."
+echo
+echo Press <return> to start the new guest.
+read bogus
+
+echo
+echo 'Starting new guest, attaching to console. Exit with Ctrl+]'
+echo
+
+virsh start $vmname
+sleep 2
+virsh attach-device $vmname $VARDIR/$vmname-disk-attach.xml
+virsh console $vmname
+
+#do we really need to detach the cloud-init disk ?
+#virsh detach-device $vmname $VARDIR/$vmname-disk-attach.xml
+
+
diff --git a/libvirt-make-seed-disk b/libvirt-make-seed-disk
new file mode 100755
index 0000000..01e386f
--- /dev/null
+++ b/libvirt-make-seed-disk
@@ -0,0 +1,152 @@
+#!/bin/bash
+VERBOSITY=0
+TEMP_D=""
+DEF_DISK_FORMAT="raw"
+#DEF_FILESYSTEM="iso9660"
+DEF_FILESYSTEM="vfat"
+
+error() { echo "$@" 1>&2; }
+errorp() { printf "$@" 1>&2; }
+fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
+failp() { [ $# -eq 0 ] || errorp "$@"; exit 1; }
+
+Usage() {
+ cat <<EOF
+Usage: ${0##*/} [ options ] output user-data [meta-data]
+
+ Create a disk for cloud-init to utilize nocloud
+
+ options:
+ -h | --help show usage
+ -d | --disk-format D disk format to output. default: raw
+ -f | --filesystem F filesystem format (vfat or iso), default: iso9660
+
+ -i | --interfaces F write network interfaces file into metadata
+ -m | --dsmode M add 'dsmode' ('local' or 'net') to the metadata
+ default in cloud-init is 'net', meaning network is
+ required.
+
+ Example:
+ * cat my-user-data
+ #cloud-config
+ password: passw0rd
+ chpasswd: { expire: False }
+ ssh_pwauth: True
+ * echo "instance-id: \$(uuidgen || echo i-abcdefg)" > my-meta-data
+ * ${0##*/} my-seed.img my-user-data my-meta-data
+ * kvm -net nic -net user,hostfwd=tcp::2222-:22 \\
+ -drive file=disk1.img,if=virtio -drive file=my-seed.img,if=virtio
+ * ssh -p 2222 ubuntu@localhost
+EOF
+}
+
+bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; }
+cleanup() {
+ [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
+}
+
+debug() {
+ local level=${1}; shift;
+ [ "${level}" -gt "${VERBOSITY}" ] && return
+ error "${@}"
+}
+
+short_opts="hi:d:f:m:o:v"
+long_opts="disk-format:,dsmode:,filesystem:,help,interfaces:,output:,verbose"
+getopt_out=$(getopt --name "${0##*/}" \
+ --options "${short_opts}" --long "${long_opts}" -- "$@") &&
+ eval set -- "${getopt_out}" ||
+ bad_Usage
+
+## <<insert default variables here>>
+output=""
+userdata=""
+metadata=""
+filesystem=$DEF_FILESYSTEM
+diskformat=$DEF_DISK_FORMAT
+interfaces=_unset
+dsmode=""
+
+
+while [ $# -ne 0 ]; do
+ cur=${1}; next=${2};
+ case "$cur" in
+ -h|--help) Usage ; exit 0;;
+ -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
+ -d|--disk-format) diskformat=$next; shift;;
+ -f|--filesystem) filesystem=$next; shift;;
+ -m|--dsmode) dsmode=$next; shift;;
+ -i|--interfaces) interfaces=$next; shift;;
+ --) shift; break;;
+ esac
+ shift;
+done
+
+## check arguments here
+## how many args do you expect?
+[ $# -ge 2 ] || bad_Usage "must provide output, userdata"
+[ $# -le 3 ] || bad_Usage "confused by additional args"
+
+output=$1
+userdata=$2
+metadata=$3
+
+[ -n "$metadata" -a "${interfaces}" != "_unset" ] &&
+ fail "metadata and --interfaces are incompatible"
+[ -n "$metadata" -a -n "$dsmode" ] &&
+ fail "metadata and dsmode are incompatible"
+[ "$interfaces" = "_unset" -o -r "$interfaces" ] ||
+ fail "$interfaces: not a readable file"
+
+TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
+ fail "failed to make tempdir"
+trap cleanup EXIT
+
+if [ -n "$metadata" ]; then
+ cp "$metadata" "$TEMP_D/meta-data" || fail "$metadata: failed to copy"
+else
+ iface_data=""
+ dsmode_data=""
+ [ "$interfaces" != "_unset" ] &&
+ iface_data=$(sed ':a;N;$!ba;s/\n/\\n/g' "$interfaces") &&
+ iface_data="\"interfaces\": '$iface_data'"
+ [ -n "$dsmode" ] && dsmode_data="\"dsmode\": \"$dsmode\""
+ printf "{\n%s\n%s\n%s\n}" "\"instance-id\": \"iid-local01\"" \
+ "${iface_data}" "${dsmode_data}" > "${TEMP_D}/meta-data"
+fi
+
+if [ "$userdata" = "-" ]; then
+ cat > "$TEMP_D/user-data" || fail "failed to read from stdin"
+else
+ cp "$userdata" "$TEMP_D/user-data" || fail "$userdata: failed to copy"
+fi
+
+## alternatively, create a vfat filesystem with same files
+img="$TEMP_D/seed.img"
+truncate --size 100K "$img" || fail "failed truncate image"
+
+case "$filesystem" in
+ iso9660|iso)
+ genisoimage -output "$img" -volid cidata \
+ -joliet -rock "$TEMP_D/user-data" "$TEMP_D/meta-data" \
+ > "$TEMP_D/err" 2>&1 ||
+ { cat "$TEMP_D/err" 1>&2; fail "failed to genisoimage"; }
+ ;;
+ vfat)
+ mkfs.vfat -n cidata "$img" || fail "failed mkfs.vfat"
+ mcopy -oi "$img" "$TEMP_D/user-data" "$TEMP_D/meta-data" :: ||
+ fail "failed to copy user-data, meta-data to img"
+ ;;
+ *) fail "unknown filesystem $filesystem";;
+esac
+
+[ "$output" = "-" ] && output="$TEMP_D/final"
+qemu-img convert -f raw -O "$diskformat" "$img" "$output" ||
+ fail "failed to convert to disk format $diskformat"
+
+[ "$output" != "$TEMP_D/final" ] || { cat "$output" && output="-"; } ||
+ fail "failed to write to -"
+
+error "wrote ${output} with filesystem=$filesystem and diskformat=$diskformat"
+# vi: ts=4 noexpandtab
+
diff --git a/libvirt-write-disk-attach-xml b/libvirt-write-disk-attach-xml
new file mode 100755
index 0000000..e813452
--- /dev/null
+++ b/libvirt-write-disk-attach-xml
@@ -0,0 +1,23 @@
+#!/bin/sh -f
+
+disks="$1" && [ -n "$disks" ] ||
+ { echo "must give disk image"; exit 1; }
+name=${2:-my-example-dom}
+devs=bcdefghij
+n=0
+for disk in "$@"; do
+ disk=$(readlink -f "$disk") || { echo "failed to get path to $disk" 1>&2; exit 1; }
+ t=${devs#?}
+ dev=vd${devs%${t}}
+ devs=${devs#?}
+ n=$(($n+1))
+ cat <<EOF
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='raw'/>
+ <source file='$disk'/>
+ <target dev='$dev' bus='virtio'/>
+ <boot order='$n'/>
+ </disk>
+EOF
+done
+