storage: Add infrastructure to manage XML namespace options

Introduce the virStoragePoolFSMountOptionsDef to be used to
manage the Storage Pool XML Namespace for mount options.

Using a new virStorageBackendNamespaceInit function, set the
virStoragePoolXMLNamespace into the _virStoragePoolOptions when
the storage backend is loaded.

Modify the storagepool.rng to allow for the usage of a different
XML namespace to parse the fs_mount_opts to be included with
the fs and netfs storage pool definitions.

Modify the storagepoolxml2xmltest to utilize a properly modified
XML file to parse and format the namespace for a netfs storage pool.

Signed-off-by: John Ferlan <jferlan@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
John Ferlan 2019-01-07 17:14:57 -05:00
parent fa7a66d079
commit 7a227688a8
9 changed files with 307 additions and 1 deletions

View File

@ -508,6 +508,69 @@
device, measured in bytes. <span class="since">Since 0.4.1</span>
</p>
<h3><a id="StoragePoolNamespaces">Storage Pool Namespaces</a></h3>
<p>
Usage of Storage Pool Namespaces provides a mechanism to provide
pool type specific data in a free form or arbitrary manner via
XML syntax targeted solely for the needs of the specific pool type
which is not otherwise supported in standard XML. For the "fs" and
"netfs" pool types this provides a mechanism to provide additional
mount options on the command line.
</p>
<p>
Usage of namespaces comes with no support guarantees. It is intended
for developers testing out a concept prior to requesting an explicitly
supported XML option in libvirt, and thus should never be used in
production.
</p>
<dl>
<dt><code>fs:mount_opts</code></dt>
<dd>Provides an XML namespace mechanism to optionally utilize
specifically named options for the mount command via the "-o"
option for the <code>fs</code> or <code>netfs</code> type storage
pools. In order to designate that the Storage Pool will be using
the mechanism, the <code>pool</code> element must be modified to
provide the XML namespace attribute syntax as follows:
<p>
xmlns:fs='http://libvirt.org/schemas/storagepool/source/fs/1.0'
</p>
<p>
The <code>fs:mount_opts</code> defines the mount options by
specifying multiple <code>fs:option</code> subelements with
the attribute <code>name</code> specifying the mount option to
be added. The value of the named option is not checked since
it's possible options don't exist on all distributions. It is
expected that proper and valid options will be supplied for the
target host.
</p>
The following XML snippet shows the syntax required in order to
utilize for a netfs pool:
<pre>
&lt;pool type="netfs" xmlns:fs='http://libvirt.org/schemas/storagepool/source/fs/1.0'&gt;
&lt;name&gt;nfsimages&lt;/name&gt;
...
&lt;source&gt;
...
&lt;/source&gt;
...
&lt;target&gt;
...
&lt;/target&gt;
&lt;fs:mount_opts&gt;
&lt;fs:option name='sync'/&gt;
&lt;fs:option name='lazytime'/&gt;
&lt;/fs:mount_opts&gt;
&lt;/pool&gt;
...</pre>
<span class="since">Since 5.1.0.</span></dd>
</dl>
<h2><a id="StorageVol">Storage volume XML</a></h2>
<p>
A storage volume will generally be either a file or a device

View File

@ -52,6 +52,9 @@
<ref name='sourcefs'/>
<ref name='target'/>
</interleave>
<optional>
<ref name='fs_mount_opts'/>
</optional>
</define>
<define name='poolnetfs'>
@ -64,6 +67,9 @@
<ref name='sourcenetfs'/>
<ref name='target'/>
</interleave>
<optional>
<ref name='fs_mount_opts'/>
</optional>
</define>
<define name='poollogical'>
@ -682,4 +688,21 @@
</data>
</define>
<!--
Optional storage pool extensions in their own namespace:
"fs" or "netfs"
-->
<define name="fs_mount_opts">
<element name="mount_opts" ns="http://libvirt.org/schemas/storagepool/source/fs/1.0">
<zeroOrMore>
<element name="option">
<attribute name='name'>
<text/>
</attribute>
</element>
</zeroOrMore>
</element>
</define>
</grammar>

View File

@ -41,6 +41,7 @@ VIR_LOG_INIT("storage.storage_backend_fs");
#if WITH_STORAGE_FS
# include <libxml/xpathInternals.h>
# include <mntent.h>
struct _virNetfsDiscoverState {
@ -559,6 +560,122 @@ virStorageBackendFileSystemBuild(virStoragePoolObjPtr pool,
}
#if WITH_STORAGE_FS
# define STORAGE_POOL_FS_NAMESPACE_HREF "http://libvirt.org/schemas/storagepool/source/fs/1.0"
/* Backend XML Namespace handling for fs or netfs specific mount options to
* be added to the mount -o {options_list} command line that are not otherwise
* supplied by supported XML. The XML will use the format, such as:
*
* <fs:mount_opts>
* <fs:option name='sync'/>
* <fs:option name='lazytime'/>
* </fs:mount_opts>
*
* and the <pool type='fs'> or <pool type='netfs'> is required to have a
* "xmlns:fs='%s'" attribute using the STORAGE_POOL_FS_NAMESPACE_HREF
*/
static void
virStoragePoolDefFSNamespaceFree(void *nsdata)
{
virStoragePoolFSMountOptionsDefPtr cmdopts = nsdata;
size_t i;
if (!cmdopts)
return;
for (i = 0; i < cmdopts->noptions; i++)
VIR_FREE(cmdopts->options[i]);
VIR_FREE(cmdopts->options);
VIR_FREE(cmdopts);
}
static int
virStoragePoolDefFSNamespaceParse(xmlXPathContextPtr ctxt,
void **data)
{
virStoragePoolFSMountOptionsDefPtr cmdopts = NULL;
xmlNodePtr *nodes = NULL;
int nnodes;
size_t i;
int ret = -1;
if (xmlXPathRegisterNs(ctxt, BAD_CAST "fs",
BAD_CAST STORAGE_POOL_FS_NAMESPACE_HREF) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to register xml namespace '%s'"),
STORAGE_POOL_FS_NAMESPACE_HREF);
return -1;
}
nnodes = virXPathNodeSet("./fs:mount_opts/fs:option", ctxt, &nodes);
if (nnodes < 0)
return -1;
if (nnodes == 0)
return 0;
if (VIR_ALLOC(cmdopts) < 0 ||
VIR_ALLOC_N(cmdopts->options, nnodes) < 0)
goto cleanup;
for (i = 0; i < nnodes; i++) {
if (!(cmdopts->options[cmdopts->noptions] =
virXMLPropString(nodes[i], "name"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("no fs mount option name specified"));
goto cleanup;
}
cmdopts->noptions++;
}
VIR_STEAL_PTR(*data, cmdopts);
ret = 0;
cleanup:
VIR_FREE(nodes);
virStoragePoolDefFSNamespaceFree(cmdopts);
return ret;
}
static int
virStoragePoolDefFSNamespaceFormatXML(virBufferPtr buf,
void *nsdata)
{
size_t i;
virStoragePoolFSMountOptionsDefPtr def = nsdata;
if (!def)
return 0;
virBufferAddLit(buf, "<fs:mount_opts>\n");
virBufferAdjustIndent(buf, 2);
for (i = 0; i < def->noptions; i++)
virBufferEscapeString(buf, "<fs:option name='%s'/>\n",
def->options[i]);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</fs:mount_opts>\n");
return 0;
}
static const char *
virStoragePoolDefFSNamespaceHref(void)
{
return "xmlns:fs='" STORAGE_POOL_FS_NAMESPACE_HREF "'";
}
#endif /* WITH_STORAGE_FS */
virStorageBackend virStorageBackendDirectory = {
.type = VIR_STORAGE_POOL_DIR,
@ -617,6 +734,13 @@ virStorageBackend virStorageBackendNetFileSystem = {
.downloadVol = virStorageBackendVolDownloadLocal,
.wipeVol = virStorageBackendVolWipeLocal,
};
static virStoragePoolXMLNamespace virStoragePoolFSXMLNamespace = {
.parse = virStoragePoolDefFSNamespaceParse,
.free = virStoragePoolDefFSNamespaceFree,
.format = virStoragePoolDefFSNamespaceFormatXML,
.href = virStoragePoolDefFSNamespaceHref,
};
#endif /* WITH_STORAGE_FS */
@ -630,8 +754,16 @@ virStorageBackendFsRegister(void)
if (virStorageBackendRegister(&virStorageBackendFileSystem) < 0)
return -1;
if (virStorageBackendNamespaceInit(VIR_STORAGE_POOL_FS,
&virStoragePoolFSXMLNamespace) < 0)
return -1;
if (virStorageBackendRegister(&virStorageBackendNetFileSystem) < 0)
return -1;
if (virStorageBackendNamespaceInit(VIR_STORAGE_POOL_NETFS,
&virStoragePoolFSXMLNamespace) < 0)
return -1;
#endif /* WITH_STORAGE_FS */
return 0;

View File

@ -82,6 +82,22 @@
VIR_LOG_INIT("storage.storage_util");
/* virStorageBackendNamespaceInit:
* @poolType: virStoragePoolType
* @xmlns: Storage Pool specific namespace callback methods
*
* To be called during storage backend registration to configure the
* Storage Pool XML Namespace based on the backend's needs.
*/
int
virStorageBackendNamespaceInit(int poolType,
virStoragePoolXMLNamespacePtr xmlns)
{
return virStoragePoolOptionsPoolTypeSetXMLNamespace(poolType, xmlns);
}
#define READ_BLOCK_SIZE_DEFAULT (1024 * 1024)
#define WRITE_BLOCK_SIZE_DEFAULT (4 * 1024)

View File

@ -26,6 +26,20 @@
# include "storage_driver.h"
# include "storage_backend.h"
/* Storage Pool Namespace options to share w/ storage_backend_fs.c and
* the virStorageBackendFileSystemMountCmd method */
typedef struct _virStoragePoolFSMountOptionsDef virStoragePoolFSMountOptionsDef;
typedef virStoragePoolFSMountOptionsDef *virStoragePoolFSMountOptionsDefPtr;
struct _virStoragePoolFSMountOptionsDef {
size_t noptions;
char **options;
};
int
virStorageBackendNamespaceInit(int poolType,
virStoragePoolXMLNamespacePtr xmlns);
/* File creation/cloning functions used for cloning between backends */
int

View File

@ -937,7 +937,9 @@ storagevolxml2xmltest_LDADD = $(LDADDS)
storagepoolxml2xmltest_SOURCES = \
storagepoolxml2xmltest.c \
testutils.c testutils.h
storagepoolxml2xmltest_LDADD = $(LDADDS)
storagepoolxml2xmltest_LDADD = $(LDADDS) \
../src/libvirt_driver_storage_impl.la \
$(GNULIB_LIBS)
nodedevxml2xmltest_SOURCES = \
nodedevxml2xmltest.c \

View File

@ -0,0 +1,25 @@
<pool type='netfs' xmlns:fs='http://libvirt.org/schemas/storagepool/source/fs/1.0'>
<name>nfsimages</name>
<uuid>7641d5a8-af11-f730-a34e-0a7dfcede71f</uuid>
<capacity>0</capacity>
<allocation>0</allocation>
<available>0</available>
<source>
<host name='localhost'/>
<dir path='/var/lib/libvirt/images'/>
<format type='nfs'/>
<protocol ver='3'/>
</source>
<target>
<path>/mnt</path>
<permissions>
<mode>0700</mode>
<owner>0</owner>
<group>0</group>
</permissions>
</target>
<fs:mount_opts>
<fs:option name='sync'/>
<fs:option name='lazytime'/>
</fs:mount_opts>
</pool>

View File

@ -0,0 +1,25 @@
<pool type='netfs' xmlns:fs='http://libvirt.org/schemas/storagepool/source/fs/1.0'>
<name>nfsimages</name>
<uuid>7641d5a8-af11-f730-a34e-0a7dfcede71f</uuid>
<capacity unit='bytes'>0</capacity>
<allocation unit='bytes'>0</allocation>
<available unit='bytes'>0</available>
<source>
<host name='localhost'/>
<dir path='/var/lib/libvirt/images'/>
<format type='nfs'/>
<protocol ver='3'/>
</source>
<target>
<path>/mnt</path>
<permissions>
<mode>0700</mode>
<owner>0</owner>
<group>0</group>
</permissions>
</target>
<fs:mount_opts>
<fs:option name='sync'/>
<fs:option name='lazytime'/>
</fs:mount_opts>
</pool>

View File

@ -11,6 +11,8 @@
#include "testutilsqemu.h"
#include "virstring.h"
#include "storage/storage_util.h"
#define VIR_FROM_THIS VIR_FROM_NONE
static int
@ -70,6 +72,9 @@ mymain(void)
testCompareXMLToXMLHelper, (name)) < 0) \
ret = -1
if (storageRegisterAll() < 0)
return EXIT_FAILURE;
DO_TEST("pool-dir");
DO_TEST("pool-dir-naming");
DO_TEST("pool-fs");
@ -86,6 +91,7 @@ mymain(void)
DO_TEST("pool-netfs-protocol-ver");
DO_TEST("pool-netfs-gluster");
DO_TEST("pool-netfs-cifs");
DO_TEST("pool-netfs-ns-mountopts");
DO_TEST("pool-scsi");
DO_TEST("pool-scsi-type-scsi-host");
DO_TEST("pool-scsi-type-fc-host");