Hello!
I had a hobby project where I needed to manipulate xen disk images on
remote systems, that used a model similar to libirt's remote support.
Based on what I learnt from it, I came up with a possible model for
libvirt's remote storage support. I present it here for discussion.
We typically store the images in volumes on LVM, or in dedicated file
system folders.
The folders and volume groups usable by libvirt can be limited in a
config file.
It is probably not neccessary to differentiate between defined and
created files, as you can not stop and start a file like a domain, you
either have it on disk, or not.
Libvirt should not store information on these files, everything should
be checked/listed on the fly, so that if you just copy an image to a
directory, libvirt can deduct all information (well, all it can) on it,
and handle it just as if the file was created by it.
The handle for the file is its path, plus its virConnect object (i.e.
the host it is on). For consistency, it may be possible to create an
object for it, but as disk images have no persistent properties apart
from what is on the disk, and it can always be checked from there, it
provides no extra functionality.
I think there is no need to support remote files explicitly, as the
domains mount local files/volumes. The file/volume may actually be
mounted from a NAS or SAN, of course, but it does not matter because we
use the local path names, and AFAIK all virtualization tools use local
files or local devices as blockdevs.
I have added compression to the mix because it is immensely useful.
I have used lzop in my project, and a full backup and restore was much
faster when using a compressed backup file, than with and uncrompessed
one. It conserves disk space, as well as cpu/bus capacity.
Zeroing out newly allocated files, helps with compressed backups, as
well as security. It also means that no holey files can be used.
The objects we are dealing with are disk images.
They have the following properties:
-Path: The unix path of the file ( /mnt/images/fc7.img or /dev/VG/fc7)
-Compression: Mountable/compressed
-Type: Plain file/LVM volume/ What else?
-Size
-Filesystem: swap/ext3/xfs/....
-Is it mounted?
We can do the following operations on the images:
Create
-connection
-filepath
-size
Allocates a new image of the given type, size, and name.
Libvirt should parse the filepath, and determine the base path, check if
it's a directory or a VG, check if libvirt is allowed to operate on the
path/VG, then create the file/volume.
For security reasons zeroing out the allocated space should be a
non-optional step of the allocation.
DirectoryList
-connection
-directorypath
Plain ls functionality, that returns the list of files, and any
subdirectories. If called on a VG, it returns the volumes in it.
Info
-connection
-filepath
Returns information on the given file/volume, including size, type,
filesystem (if
available), whether it is a snapshot (if a volume), and whether it is
mounted or not.
size can be determined by ls or lvinfo, filesystem by 'file' command.
Delete
-connection
-filepath
Delete the file/volume. Find out if it's a file or volume, and rm or
lvremove it.
Grow
-connection
-path
-filename
-newsize
Grows the specified image to the given size. The newly added space is zeroed
out.
Shrink?
-connection
-path
-filename
-newsize
Shrinks the specified image the the given size. It's very tricky,
because to avoid data loss, we need to analyze the file system size. Of
course, we can just say that it's the reponsibility of the user, after
all, we allow him to outright delete the file as well.
We may combine it with Grow, and call it Resize.
Growfs
-connection
-path
-filename
-newsize?
Grows the filesystem on the image to fill the size of the image, or the
given newsize.
Can only be used on umounted images.
It is neccesary because some filesystems may not be grown while mounted,
so the guest can not do it on its own.
Shrinkfs
-connection
-path
-filname
-newsize
Shrinks the filesystem to the given size. Same coniderations apply as
with growfs, may be combined to Resizefs?
Snapshot
-connection
-filepath
-filesize
Creates a snapshot of the given image. It is only possible with images
on LVM. Should return the snapshot image name. The snapshot can later be
deleted with Delete.
CopyTo
-connection
-source filepath
-target connection
-target filepath
-snapshot flag
-archive flag
-overwrite flag
Copy the source image to the target image.
If connection is on another machine, then it's a network copy.
If the snapshot flag is true, then first create a snapshot of the source
image, copy that, then delete the snapshot.
If the archive flag is active, then the target file will be archive file
(compressed).
If the overwite flag is active, then the target file is overwitten, if
it exists. Otherwise existing files are not changed.
Even if the source file is compressed, the target file is uncompressed,
unless the archive flag is set.
CopyContents
-connection
-source filepath
-target connection
-target filepath
-snapshot flag
Copies the contents of the source file to the target file. The target
file must already exist, and be no smaller than the source file. The
contents of the target file are overwitten, and any extra space is
zeroed out.
Archive
-connection
-filepath
compresses the given file. Makes sense only on files, not volumes.
Unarchive
-connection
-filepath
uncompresses the given file. Makes sense only on archved(compressed) files.
StorageInfo
- connection
Returns information on the node's storage configuration. What kind of
filesystems it can handle, What are the accessible file / VG paths,
what's the free space on them, etc.
A typical usage scenario could be something like this:
Aconn=getVirconn("ssh:Ahost"); //Open the connection to host A
Bconn=getVirconn("ssh:Bhost"); //Host B will hold our backup image
Ainfo=StorageInfo(Aconn); //Get Ainfo
AVGPath = <get the first usable VG path from VG info>
Newimage = Create(Aconn, concat("AVGPath", "newimage", 100000);
//A
100Mb volume is created and zeroed out.
CopyContents(Aconn, NewImage, Aconn, "/images/ghost/FC7default.img",
no); //Copy our pre-created FC7 image to the new image
Growfs(Aconn, NewImage, 0); //Grow the copied filesystem to fill the
whole volume.
<Here we define a new domain, and use NewImage as the name of the
backing image for the guest's block device>
<Start the new domain>
Copy(Aconn, NewImage, Bconn, "/mnt/backups/backup23image", snapshot=yes,
archive=yes, overwrite=no);
//Make an LVM snapshot of NewImage, and copy it to Host B on the given
filename, compressing it on the fly, then remove the snapshot
<Stop the domain>
CopyContents(Bconn, "/mnt/backups/backup23image", Aconn, NewImage,
snapshot=no); //Restore the backed-up image to NewImage, decompress it
on the fly.
<Start the domain>
<Stop the domain>
Grow(Aconn, NewImage, 200000); //Grow the volume to 200MBs
Growfs(Aconn, NewImage); //Grow the fs on the volume to fill the volume
<Start the domain>
.....
Best regards
István