[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libvir] Proposal for the storage API (for discussion only)



This is an outline for the storage API, for discussion only. It is mostly unimplemented, but presented as a kind of "literate patch", so you can read the API calls and how they could be implemented.

I've tried to follow as far as possible operations which are needed in order to make virt-install / virt-manager work in the remote case, and also to support discovery and creation of partitions / LVs / iSCSI LUNs.

The new API calls are:

  virStorageFileLocations
	- returns a list of locations which can be used
	  for creating file-backed guests

  virStorageFileStat
  virStorageFileStatVFS
  virStorageCreateFile
	- for creating file-backed guest storage

  virStorageListGroups
  virStorageCreateVolume
	- for discovering and creating partitions, LVs, LUNs, &c.

Rich.

--
Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/
Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod
Street, Windsor, Berkshire, SL4 1TE, United Kingdom.  Registered in
England and Wales under Company Registration No. 03798903
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.103
diff -u -p -r1.103 libvirt.c
--- src/libvirt.c	15 Oct 2007 21:38:56 -0000	1.103
+++ src/libvirt.c	18 Oct 2007 17:03:06 -0000
@@ -3357,6 +3357,356 @@ virNetworkSetAutostart(virNetworkPtr net
     return -1;
 }
 
+/*----------------------------------------------------------------------*/
+/* The storage API starts here. */
+
+/**
+ * virStorageFileLocations:
+ * @conn: pointer to the hypervisor connection
+ * @len: length of array returned (OUT)
+ *
+ * Some hypervisors only allow file-backed storage in certain disk
+ * locations.  This function returns an array of permitted locations
+ * (wildcards).
+ *
+ * A candidate path may be checked against the list of wildcards by
+ * using the POSIX.2 function fnmatch with FNM_PATHNAME flag set.
+ *
+ * Note that wildcards can describe more than just a simple
+ * directory (eg. "/var/lib/xen/images/xen*.img").
+ *
+ * Returns array of 'names' on success or NULL on failure.
+ *
+ * On success, 'names' and 'len' describe an array of strings
+ * of length len.  After use, the caller should use
+ * virStorageFileLocationsFree to free the array.
+ */
+char **
+virStorageFileLocations (virConnectPtr conn, size_t *len)
+{
+    DEBUG("conn=%p, len=%p", conn, len);
+
+    /*
+      Implementation notes:
+
+      /etc/libvirt/libvirt.conf contains the list of wildcards
+      permitted for each hypervisor.  There is a default list
+      or the system administrator can override.
+
+      ---- /etc/libvirt/libvirt.conf ----------
+
+      file_locations[xen] = [ "/var/lib/xen/images/ *.img" ]
+
+      file_locations[qemu] = [ "/var/lib/qemu/ *" ]
+                                      # ^^ can't put / * in a C comment
+      --------------------
+
+      Although there are different paths returned for each
+      hypervisor type, we can centralise the code in this
+      function.  Remote will still need to be done by the remote
+      driver.
+     */
+    TODO;
+    return NULL;
+}
+
+/**
+ * virStorageFileLocationsFree:
+ * @conn: pointer to the hypervisor connection
+ * @names: array of names
+ * @len: length of array
+ *
+ * Free the list of storage locations previously returned by
+ * virStorageFileLocations.
+ *
+ * Returns 0 on success or -1 on failure.
+ */
+int
+virStorageFileLocationsFree (virConnectPtr conn, char **names, size_t len)
+{
+    int i;
+    DEBUG("conn=%p, names=%p, len=%zi", conn, names, len);
+
+    if (!names) {
+        virLibConnError (conn, VIR_ERR_INVALID_ARG, "names");
+        return -1;
+    }
+
+    for (i = 0; i < len; ++i)
+        free (names[i]);
+    free (names);
+    return 0;
+}
+
+/**
+ * virStorageFileStat:
+ * @conn: pointer to the hypervisor connection
+ * @path: pathname of file
+ * @statbuf: pointer to caller-allocated stat buffer (OUT)
+ * @size: caller should set this to sizeof(*statbuf).
+ *
+ * This does a stat or equivalent operation on the file named by
+ * 'path'.
+ *
+ * The hypervisor may reject the request if the file does not match
+ * a valid location (see virStorageFileLocations) or an acceptable
+ * block device name.
+ *
+ * Returns 0 if successful and the file exists ('statbuf' structure
+ * is filled in this case).  Returns 1 if the file does not exist.
+ * Returns -1 if there is an error.
+ */
+int
+virStorageFileStat (virConnectPtr conn, const char *path,
+                    virStorageStatBufferPtr statbuf, size_t size)
+{
+    DEBUG("conn=%p, path=%s, statbuf=%p, size=%zu", conn, path, statbuf, size);
+
+    /*
+      Implementation notes:
+
+      Check the path against permitted locations.
+
+      Use stat(2).
+
+      For block devices, do an additional lseek because the
+      st_size field is always 0.
+
+      virStorageStatBuffer is greatly simplified, hopefully
+      doesn't make any Unix assumptions.
+    */
+    TODO;
+    return -1;
+}
+
+/**
+ * virStorageFileStatVFS:
+ * @conn: pointer to the hypervisor connection
+ * @path: pathname of a file on the filesystem
+ * @statvfsbuf: pointer to caller-allocated stat buffer (OUT)
+ * @size: caller should set this to sizeof(*statvfsbuf).
+ *
+ * This does a statvfs or equivalent operation on the filesystem.
+ * You can use this to find out how much disk space is available
+ * for file-backed guests to use.
+ *
+ * The hypervisor may reject the request if the file does not
+ * match a valid location (see virStorageFileLocations).
+ *
+ * Note that this call will fail if 'path' does not exist, which
+ * is typically the case when you are creating a file-backed
+ * guest.  Instead pass the parent directory name as 'path' by
+ * chopping off everything after the final '/' character.
+ *
+ * Returns 0 if successful ('statvfsbuf' structure is filled in).
+ * Returns -1 if there was an error.
+ */
+int
+virStorageFileStatVFS (virConnectPtr conn, const char *path,
+                       virStorageStatVFSBufferPtr statvfsbuf, size_t size)
+{
+    DEBUG("conn=%p, path=%s, statvfsbuf=%p, size=%zu", conn, path, statvfsbuf, size);
+
+    /*
+      Implementation notes:
+
+      Check the path against permitted locations.
+
+      Use statvfs(2).
+
+      virStorageStatVFSBuffer is greatly simplified, hopefully
+      doesn't make any Unix assumptions.
+    */
+    TODO;
+    return -1;
+}
+
+/**
+ * virStorageCreateFile:
+ * @conn: pointer to the hypervisor connection
+ * @path: pathname of file
+ * @size: size (in kilobytes)
+ * @flags: flags
+ *
+ * This creates an empty file which can be used as storage (a disk
+ * image) for file-backed guests.
+ *
+ * 'path' is the full pathname of the file.
+ *
+ * 'size' is the size to create (in KB).
+ *
+ * 'flags' is a set of flags.  Currently only VIR_STORAGE_SPARSE_FILE
+ * is defined, which means to create a sparse file.
+ *
+ * The hypervisor may reject the file creation if the file does not
+ * a valid location (see virStorageFileLocations), or if the file exists
+ * already (see also virStorageFileStat), or if there is not enough
+ * disk space even in sparse mode for the full file (see also
+ * virStorageFileStatVFS).
+ *
+ * File creation can be a lengthy operation, and there is currently
+ * no way to get any updates on the progress of the operation.
+ *
+ * Returns 0 on success or -1 on failure.
+ */
+int
+virStorageCreateFile (virConnectPtr conn, const char *path,
+                      unsigned long long size, int flags)
+{
+    DEBUG("conn=%p, path=%s, size=%llu, flags=%d", conn, path, size, flags);
+
+    /*
+      Implementation notes:
+
+      Check the path against permitted locations.
+
+      Check the file doesn't exist.
+
+      Check enough space using statvfs.
+
+      Create the file.
+    */
+    TODO;
+    return -1;
+}
+
+/**
+ * virStorageListGroups:
+ * @conn: pointer to the hypervisor connection
+ * @len: length of returned array (OUT)
+ *
+ * This lists out the available storage groups and some extra information
+ * about each one such as name and amount of free space.
+ *
+ * Callers can use this to present lists of available storage for
+ * partition-backed guests, in conjunction with the
+ * virStorageCreateVolume call.
+ *
+ * Returns an array of 'groups' on success or NULL on failure.
+ *
+ * On success, 'groups' and 'len' describe an array of virStorageGroupPtr
+ * of length len.  After use, the caller should use
+ * virStorageListGroupsFree to free the array.
+ */
+virStorageGroupPtr *
+virStorageListGroups (virConnectPtr conn, size_t *len)
+{
+    DEBUG("conn=%p, len=%p", conn, len);
+
+    /*
+      Implementation notes:
+
+      ---- /etc/libvirt/libvirt.conf ----------
+
+      list_groups =
+        "vgs --noheadings --nosuffix --units k --separator : --unbuffered |
+         vgs2xml"
+
+      --------------------
+
+      The scriptlet will be different depending on the underlying
+      technology.  In the instance above, it's Linux LVM & volume
+      groups.  It might also be sfdisk (for partitions), iscsiadm
+      (for iSCSI), or some sort of proprietary SAN command.
+
+      vgs2xml is a command that we supply which takes the output
+      of vgs and formats it to some standard XML.
+
+      This code runs the scriptlet and parses the XML into
+      virStorageGroup structures.
+    */
+    TODO;
+    return NULL;
+}
+
+/**
+ * virStorageListGroupsFree:
+ * @conn: pointer to the hypervisor connection
+ * @groups: array of groups
+ * @len: length of array
+ *
+ * Free the list of groups previously returned by
+ * virStorageListGroups.
+ *
+ * Returns 0 on success or -1 on failure.
+ */
+int
+virStorageListGroupsFree (virConnectPtr conn,
+                          virStorageGroupPtr *groups, size_t len)
+{
+    int i;
+    DEBUG("conn=%p, groups=%p, len=%zu", conn, groups, len);
+
+    if (!groups) {
+        virLibConnError (conn, VIR_ERR_INVALID_ARG, "groups");
+        return -1;
+    }
+
+    for (i = 0; i < len; ++i) {
+        if (groups[i]->magic != VIR_STORAGE_GROUP_MAGIC_VER1) {
+            virLibConnError (conn, VIR_ERR_INVALID_ARG, "group magic");
+            return -1;
+        }
+    }
+
+    for (i = 0; i < len; ++i) {
+        free (groups[i]->name);
+        free (groups[i]);
+    }
+    free (groups);
+    return 0;
+}
+
+/**
+ * virStorageCreateVolume:
+ * @conn: pointer to the hypervisor connection
+ * @name: volume name
+ * @group: group name
+ * @size: size (in kilobytes)
+ * @flags: (currently unused, caller should pass 0)
+ *
+ * This allocates a partition or logical volume within the named
+ * volume group ('group').
+ *
+ * Group names and available space may be found by calling
+ * virStorageListGroups.
+ *
+ * Returns the name (eg. device name) of the partition or volume
+ * if successful.  The name should be freed by the caller after
+ * use.  Returns NULL on failure.
+ */
+char *
+virStorageCreateVolume (virConnectPtr conn,
+                        const char *name, const char *group,
+                        unsigned long long size, int flags)
+{
+    DEBUG("conn=%p, name=%s, group=%s, size=%llu, flags=%d", conn, name, group,
+          size, flags);
+
+    /*
+      Implementation notes:
+
+      ---- /etc/libvirt/libvirt.conf ----------
+
+      create_volume =
+        "lvcreate -L %size -n %name %group && echo /dev/%group/%name"
+
+      --------------------
+
+      The scriptlet will be different depending on the underlying
+      technology.
+
+      The scriptlet needs to print out the device name (if created).
+
+      The %fields need to be quoted properly if they contain any
+      shell meta-characters.
+
+      This code runs the scriptlet and returns the device name.
+    */
+    TODO;
+    return NULL;
+}
+
 /*
  * vim: set tabstop=4:
  * vim: set shiftwidth=4:
Index: include/libvirt/libvirt.h.in
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h.in,v
retrieving revision 1.38
diff -u -p -r1.38 libvirt.h.in
--- include/libvirt/libvirt.h.in	15 Oct 2007 21:38:56 -0000	1.38
+++ include/libvirt/libvirt.h.in	18 Oct 2007 17:03:06 -0000
@@ -686,8 +686,76 @@ int			virNetworkGetAutostart	(virNetwork
 int			virNetworkSetAutostart	(virNetworkPtr network,
 						 int autostart);
 
+
+/* Storage structures. */
+#define VIR_STORAGE_STAT_BUFFER_TYPE_BLOCK 1 /* Block device. */
+#define VIR_STORAGE_STAT_BUFFER_TYPE_FILE  2 /* Regular file. */
+#define VIR_STORAGE_STAT_BUFFER_TYPE_DIR   3 /* Directory. */
+
+struct virStorageStatBuffer {
+    int type;                   /* Device type. */
+    unsigned long long size;    /* Size in bytes. */
+};
+typedef struct virStorageStatBuffer *virStorageStatBufferPtr;
+
+struct virStorageStatVFSBuffer {
+    unsigned long bsize;        /* Block size. */
+    unsigned long long bavail;  /* Blocks available. */
+};
+typedef struct virStorageStatVFSBuffer *virStorageStatVFSBufferPtr;
+
+#define VIR_STORAGE_GROUP_MAGIC_VER1 0x57083001
+
+#define VIR_STORAGE_GROUP_FLAGS_READONLY 1
+
+struct virStorageGroup {
+    int magic;                  /* Magic / structure version. */
+    char *name;                 /* Volume group name. */
+    int flags;                  /* Flags. */
+    unsigned long long size;    /* Total size in kilobytes. */
+    unsigned long long avail;   /* Available (free) space in kilobytes. */
+};
+typedef struct virStorageGroup *virStorageGroupPtr;
+
+/* Flags for virStorageCreateFile */
+#define VIR_STORAGE_SPARSE_FILE 1
+
+/* Storage calls. */
+char **virStorageFileLocations     (virConnectPtr conn, size_t *len);
+int    virStorageFileLocationsFree (virConnectPtr conn,
+                                    char **names, size_t len);
+int    virStorageFileStat          (virConnectPtr conn, const char *path,
+				    virStorageStatBufferPtr statbuf,
+				    size_t size);
+int    virStorageFileStatVFS       (virConnectPtr conn, const char *path,
+				    virStorageStatVFSBufferPtr statvfsbuf,
+				    size_t size);
+int    virStorageCreateFile        (virConnectPtr conn, const char *path,
+				    unsigned long long size, int flags);
+virStorageGroupPtr *
+       virStorageListGroups        (virConnectPtr conn, size_t *len);
+int    virStorageListGroupsFree    (virConnectPtr conn,
+                                    virStorageGroupPtr *groups, size_t len);
+char * virStorageCreateVolume      (virConnectPtr conn,
+                                    const char *name, const char *group,
+                                    unsigned long long size, int flags);
+
 #ifdef __cplusplus
 }
 #endif
 
 #endif /* __VIR_VIRLIB_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]