[libvirt] libguestfs integration: rich disk access for libvirt applications

Richard W.M. Jones rjones at redhat.com
Thu Sep 29 12:31:35 UTC 2011


On Wed, Sep 28, 2011 at 06:37:17PM +0100, Daniel P. Berrange wrote:
> We do have a historical syntax from Xen paravirt which lets us call out
> to a helper at boot time, namely the "<bootloader>" element. With Xen
> this is typically something like pygrub, or pxegrub, which does some
> work and writes out a kernel+initrd into temporary files, and prints
> the file paths + any kernel args on stdout.
> 
> We could just wire up this concept in KVM too without any real trouble,
> and then we could have guestfs-bootloader script todo the magic setup

The attached scripts show how it would work, and furthermore they show
that it really does work.

The first script is the bootloader script.  This creates the
libguestfs appliance (3 files called /tmp/kernel, /tmp/initrd and
/tmp/root).  At the moment, no caching of the appliance is
implemented, but that is easy to add.

The second script shows the sort of changes we would make to the
guestfs_add_domain API in order to run the appliance from libvirt.
It's a Ruby script that creates a transient domain, booting from the
appliance created in step 1, with the correct virtio-serial port etc.
It then tells libguestfs to connect to the virtio-serial socket.
Finally it issues some libguestfs commands to create a filesystem, so
you can tell that it is actually talking to the libguestfs daemon.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-top is 'top' for virtual machines.  Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://et.redhat.com/~rjones/virt-top
-------------- next part --------------
#!/bin/bash -

set -e

rm -f /tmp/kernel /tmp/initrd /tmp/root

# XXX Checksumming and caching not done yet.
febootstrap-supermin-helper --verbose -f ext2 \
    /usr/lib*/guestfs/supermin.d $(uname -m) \
    /tmp/kernel /tmp/initrd /tmp/root

echo "bootstrap OK"
-------------- next part --------------
#!/usr/bin/ruby

# Assumes you have run ./bootstrap to create the /tmp/kernel,
# /tmp/initrd and appliance disk (/tmp/root)

require 'libvirt'
require 'guestfs'

# Create a dummy disk for libguestfs to edit.
File.open("/tmp/disk.img", "w") {
  |f| f.seek(500*1024*1024); f.write("\0")
}

xml = <<EOF
<domain type='kvm'>
  <name>guestfs_test0</name>
  <memory>500000</memory>
  <currentMemory>500000</currentMemory>
  <vcpu>1</vcpu>
  <os>
    <type arch='x86_64'>hvm</type>
    <kernel>/tmp/kernel</kernel>
    <initrd>/tmp/initrd</initrd>
    <cmdline>panic=1 console=ttyS0 udevtimeout=300 no_timer_check
             acpi=off printk.time=1 cgroup_disable=memory selinux=0
             guestfs_verbose=1 TERM=xterm</cmdline>
  </os>
  <features>
    <apic/>
    <pae/>
  </features>

  <clock offset='utc'/>

  <on_poweroff>destroy</on_poweroff>
  <on_reboot>destroy</on_reboot>
  <on_crash>destroy</on_crash>

  <devices>
    <!-- this is the disk we are editing -->
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw'/>
      <source file='/tmp/disk.img'/>
      <target dev='vda' bus='virtio'/>
    </disk>

    <!-- the appliance disk, must be added last -->
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw'/>
      <source file='/tmp/root'/>
      <target dev='vdb' bus='virtio'/>
    </disk>

    <!-- virtio serial to talk to the guest -->
    <channel type='unix'>
      <source mode='bind' path='/tmp/socket'/>
      <target type='virtio' name='org.libguestfs.channel.0'/>
    </channel>

    <!-- XXX console? -->
    <console type='pty'>
      <target port='0'/>
    </console>

  </devices>
</domain>
EOF

begin
  File.delete("/tmp/socket")
rescue Exception
end

# Run the guest, locally for now.
conn = Libvirt::open('qemu:///session')
# 2 == autodestroy, so the domain is killed when conn is closed
dom = conn.create_domain_xml(xml, 2)

# Run libguestfs and try to connect to the socket.
g = Guestfs::Guestfs.new()
g.set_attach_method("unix:/tmp/socket")
g.set_trace(1)
g.launch()

# Send a message to the daemon to check we're talking to it OK.
r = g.echo_daemon(["one", "two", "three"])
if r != "one two three"
  raise "bad response from daemon"
end

# Do some disk operations on /tmp/disk.img.
g.part_disk("/dev/sda", "mbr")
g.mkfs("ext3", "/dev/sda1")
g.mount_options("", "/dev/sda1", "/")
g.write("/hello_world.txt", "hello from libvirt")

# Close everything.  Transient guest should go away.
g.close()
conn.close()

puts "create test run OK"
puts "/tmp/disk.img should be a complete disk image"


More information about the libvir-list mailing list