initial commit, create-guest-with-cloudinit + helper scripts
authorvarac <varacanero@zeromail.org>
Tue, 9 Oct 2012 13:50:55 +0000 (15:50 +0200)
committervarac <varacanero@zeromail.org>
Tue, 9 Oct 2012 13:50:55 +0000 (15:50 +0200)
create-guest-with-cloudinit [new file with mode: 0755]
libvirt-make-seed-disk [new file with mode: 0755]
libvirt-write-disk-attach-xml [new file with mode: 0755]

diff --git a/create-guest-with-cloudinit b/create-guest-with-cloudinit
new file mode 100755 (executable)
index 0000000..56eec5f
--- /dev/null
@@ -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 (executable)
index 0000000..01e386f
--- /dev/null
@@ -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 (executable)
index 0000000..e813452
--- /dev/null
@@ -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
+