rbd: Utilize storage pool namespace to manage config options

Allow for adjustment of RBD configuration options via Storage
Pool XML Namespace adjustments. When namespace arguments are
used to start the pool, add a VIR_WARN to indicate that the
startup was tainted by custom config_opts.

Based off original patch/concept:

https://www.redhat.com/archives/libvir-list/2014-May/msg00940.html

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-08 09:28:03 -05:00
parent ab995c1fe9
commit ab6ca81276
6 changed files with 278 additions and 4 deletions

View File

@ -516,7 +516,8 @@
XML syntax targeted solely for the needs of the specific pool type XML syntax targeted solely for the needs of the specific pool type
which is not otherwise supported in standard XML. For the "fs" and which is not otherwise supported in standard XML. For the "fs" and
"netfs" pool types this provides a mechanism to provide additional "netfs" pool types this provides a mechanism to provide additional
mount options on the command line. mount options on the command line. For the "rbd" pool this provides
a mechanism to override default settings for RBD configuration options.
</p> </p>
<p> <p>
Usage of namespaces comes with no support guarantees. It is intended Usage of namespaces comes with no support guarantees. It is intended
@ -569,6 +570,55 @@
<span class="since">Since 5.1.0.</span></dd> <span class="since">Since 5.1.0.</span></dd>
<dt><code>rbd:config_opts</code></dt>
<dd>Provides an XML namespace mechanism to optionally utilize
specifically named options for the RBD configuration options
via the rados_conf_set API for the <code>rbd</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:rbd='http://libvirt.org/schemas/storagepool/source/rbd/1.0'
</p>
<p>
The <code>rbd:config_opts</code> defines the configuration options
by specifying multiple <code>rbd:option</code> subelements with
the attribute <code>name</code> specifying the configuration option
to be added and <code>value</code> specifying the configuration
option value. The name and value for each option is only checked
to be not empty. The name and value provided are 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
<pre>
&lt;pool type="rbd" xmlns:rbd='http://libvirt.org/schemas/storagepool/source/rbd/1.0'&gt;
&lt;name&gt;myrbdpool&lt;/name&gt;
...
&lt;source&gt;
...
&lt;/source&gt;
...
&lt;target&gt;
...
&lt;/target&gt;
...
&lt;rbd:config_opts&gt;
&lt;rbd:option name='client_mount_timeout' value='45'/&gt;
&lt;rbd:option name='rados_mon_op_timeout' value='20'/&gt;
&lt;rbd:option name='rados_osd_op_timeout' value='10'/&gt;
&lt;/rbd:config_opts&gt;
&lt;/pool&gt;
</pre>
<span class="since">Since 5.1.0.</span></dd>
</dl> </dl>
<h2><a id="StorageVol">Storage volume XML</a></h2> <h2><a id="StorageVol">Storage volume XML</a></h2>

View File

@ -156,6 +156,9 @@
<ref name='sizing'/> <ref name='sizing'/>
<ref name='sourcerbd'/> <ref name='sourcerbd'/>
</interleave> </interleave>
<optional>
<ref name='rbd_config_opts'/>
</optional>
</define> </define>
<define name='poolsheepdog'> <define name='poolsheepdog'>
@ -705,4 +708,24 @@
</element> </element>
</define> </define>
<!--
Optional storage pool extensions in their own namespace:
RBD
-->
<define name="rbd_config_opts">
<element name="config_opts" ns="http://libvirt.org/schemas/storagepool/source/rbd/1.0">
<zeroOrMore>
<element name="option">
<attribute name='name'>
<text/>
</attribute>
<attribute name='value'>
<text/>
</attribute>
</element>
</zeroOrMore>
</element>
</define>
</grammar> </grammar>

View File

@ -36,6 +36,7 @@
#include "rbd/librbd.h" #include "rbd/librbd.h"
#include "secret_util.h" #include "secret_util.h"
#include "storage_util.h" #include "storage_util.h"
#include <libxml/xpathInternals.h>
#define VIR_FROM_THIS VIR_FROM_STORAGE #define VIR_FROM_THIS VIR_FROM_STORAGE
@ -50,6 +51,138 @@ struct _virStorageBackendRBDState {
typedef struct _virStorageBackendRBDState virStorageBackendRBDState; typedef struct _virStorageBackendRBDState virStorageBackendRBDState;
typedef virStorageBackendRBDState *virStorageBackendRBDStatePtr; typedef virStorageBackendRBDState *virStorageBackendRBDStatePtr;
typedef struct _virStoragePoolRBDConfigOptionsDef virStoragePoolRBDConfigOptionsDef;
typedef virStoragePoolRBDConfigOptionsDef *virStoragePoolRBDConfigOptionsDefPtr;
struct _virStoragePoolRBDConfigOptionsDef {
size_t noptions;
char **names;
char **values;
};
#define STORAGE_POOL_RBD_NAMESPACE_HREF "http://libvirt.org/schemas/storagepool/source/rbd/1.0"
static void
virStoragePoolDefRBDNamespaceFree(void *nsdata)
{
virStoragePoolRBDConfigOptionsDefPtr cmdopts = nsdata;
size_t i;
if (!cmdopts)
return;
for (i = 0; i < cmdopts->noptions; i++) {
VIR_FREE(cmdopts->names[i]);
VIR_FREE(cmdopts->values[i]);
}
VIR_FREE(cmdopts->names);
VIR_FREE(cmdopts->values);
VIR_FREE(cmdopts);
}
static int
virStoragePoolDefRBDNamespaceParse(xmlXPathContextPtr ctxt,
void **data)
{
virStoragePoolRBDConfigOptionsDefPtr cmdopts = NULL;
xmlNodePtr *nodes = NULL;
int nnodes;
size_t i;
int ret = -1;
if (xmlXPathRegisterNs(ctxt, BAD_CAST "rbd",
BAD_CAST STORAGE_POOL_RBD_NAMESPACE_HREF) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to register xml namespace '%s'"),
STORAGE_POOL_RBD_NAMESPACE_HREF);
return -1;
}
nnodes = virXPathNodeSet("./rbd:config_opts/rbd:option", ctxt, &nodes);
if (nnodes < 0)
return -1;
if (nnodes == 0)
return 0;
if (VIR_ALLOC(cmdopts) < 0)
goto cleanup;
if (VIR_ALLOC_N(cmdopts->names, nnodes) < 0 ||
VIR_ALLOC_N(cmdopts->values, nnodes) < 0)
goto cleanup;
for (i = 0; i < nnodes; i++) {
if (!(cmdopts->names[cmdopts->noptions] =
virXMLPropString(nodes[i], "name"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("no rbd option name specified"));
goto cleanup;
}
if (*cmdopts->names[cmdopts->noptions] == '\0') {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("empty rbd option name specified"));
goto cleanup;
}
if (!(cmdopts->values[cmdopts->noptions] =
virXMLPropString(nodes[i], "value"))) {
virReportError(VIR_ERR_XML_ERROR,
_("no rbd option value specified for name '%s'"),
cmdopts->names[cmdopts->noptions]);
goto cleanup;
}
if (*cmdopts->values[cmdopts->noptions] == '\0') {
virReportError(VIR_ERR_XML_ERROR,
_("empty rbd option value specified for name '%s'"),
cmdopts->names[cmdopts->noptions]);
goto cleanup;
}
cmdopts->noptions++;
}
VIR_STEAL_PTR(*data, cmdopts);
ret = 0;
cleanup:
VIR_FREE(nodes);
virStoragePoolDefRBDNamespaceFree(cmdopts);
return ret;
}
static int
virStoragePoolDefRBDNamespaceFormatXML(virBufferPtr buf,
void *nsdata)
{
size_t i;
virStoragePoolRBDConfigOptionsDefPtr def = nsdata;
if (!def)
return 0;
virBufferAddLit(buf, "<rbd:config_opts>\n");
virBufferAdjustIndent(buf, 2);
for (i = 0; i < def->noptions; i++) {
virBufferEscapeString(buf, "<rbd:option name='%s' ", def->names[i]);
virBufferEscapeString(buf, "value='%s'/>\n", def->values[i]);
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</rbd:config_opts>\n");
return 0;
}
static const char *
virStoragePoolDefRBDNamespaceHref(void)
{
return "xmlns:rbd='" STORAGE_POOL_RBD_NAMESPACE_HREF "'";
}
static int static int
virStorageBackendRBDRADOSConfSet(rados_t cluster, virStorageBackendRBDRADOSConfSet(rados_t cluster,
const char *option, const char *option,
@ -69,10 +202,11 @@ virStorageBackendRBDRADOSConfSet(rados_t cluster,
static int static int
virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr ptr, virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr ptr,
virStoragePoolSourcePtr source) virStoragePoolDefPtr def)
{ {
int ret = -1; int ret = -1;
int r = 0; int r = 0;
virStoragePoolSourcePtr source = &def->source;
virStorageAuthDefPtr authdef = source->auth; virStorageAuthDefPtr authdef = source->auth;
unsigned char *secret_value = NULL; unsigned char *secret_value = NULL;
size_t secret_value_size = 0; size_t secret_value_size = 0;
@ -183,6 +317,22 @@ virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr ptr,
rbd_default_format) < 0) rbd_default_format) < 0)
goto cleanup; goto cleanup;
if (def->namespaceData) {
virStoragePoolRBDConfigOptionsDefPtr cmdopts = def->namespaceData;
char uuidstr[VIR_UUID_STRING_BUFLEN];
for (i = 0; i < cmdopts->noptions; i++) {
if (virStorageBackendRBDRADOSConfSet(ptr->cluster,
cmdopts->names[i],
cmdopts->values[i]) < 0)
goto cleanup;
}
virUUIDFormat(def->uuid, uuidstr);
VIR_WARN("Storage Pool name='%s' uuid='%s' is tainted by custom "
"config_opts from XML", def->name, uuidstr);
}
ptr->starttime = time(0); ptr->starttime = time(0);
if ((r = rados_connect(ptr->cluster)) < 0) { if ((r = rados_connect(ptr->cluster)) < 0) {
virReportSystemError(-r, _("failed to connect to the RADOS monitor on: %s"), virReportSystemError(-r, _("failed to connect to the RADOS monitor on: %s"),
@ -256,7 +406,7 @@ virStorageBackendRBDNewState(virStoragePoolObjPtr pool)
if (VIR_ALLOC(ptr) < 0) if (VIR_ALLOC(ptr) < 0)
return NULL; return NULL;
if (virStorageBackendRBDOpenRADOSConn(ptr, &def->source) < 0) if (virStorageBackendRBDOpenRADOSConn(ptr, def) < 0)
goto error; goto error;
if (virStorageBackendRBDOpenIoCTX(ptr, pool) < 0) if (virStorageBackendRBDOpenIoCTX(ptr, pool) < 0)
@ -1277,6 +1427,7 @@ virStorageBackendRBDVolWipe(virStoragePoolObjPtr pool,
return ret; return ret;
} }
virStorageBackend virStorageBackendRBD = { virStorageBackend virStorageBackendRBD = {
.type = VIR_STORAGE_POOL_RBD, .type = VIR_STORAGE_POOL_RBD,
@ -1291,8 +1442,20 @@ virStorageBackend virStorageBackendRBD = {
}; };
static virStoragePoolXMLNamespace virStoragePoolRBDXMLNamespace = {
.parse = virStoragePoolDefRBDNamespaceParse,
.free = virStoragePoolDefRBDNamespaceFree,
.format = virStoragePoolDefRBDNamespaceFormatXML,
.href = virStoragePoolDefRBDNamespaceHref,
};
int int
virStorageBackendRBDRegister(void) virStorageBackendRBDRegister(void)
{ {
return virStorageBackendRegister(&virStorageBackendRBD); if (virStorageBackendRegister(&virStorageBackendRBD) < 0)
return -1;
return virStorageBackendNamespaceInit(VIR_STORAGE_POOL_RBD,
&virStoragePoolRBDXMLNamespace);
} }

View File

@ -0,0 +1,17 @@
<pool type='rbd' xmlns:rbd='http://libvirt.org/schemas/storagepool/source/rbd/1.0'>
<name>ceph</name>
<uuid>47c1faee-0207-e741-f5ae-d9b019b98fe2</uuid>
<source>
<name>rbd</name>
<host name='localhost' port='6789'/>
<host name='localhost' port='6790'/>
<auth username='admin' type='ceph'>
<secret uuid='2ec115d7-3a88-3ceb-bc12-0ac909a6fd87'/>
</auth>
</source>
<rbd:config_opts>
<rbd:option name='client_mount_timeout' value='45'/>
<rbd:option name='rados_mon_op_timeout' value='10'/>
<rbd:option name='rados_osd_op_timeout' value='20'/>
</rbd:config_opts>
</pool>

View File

@ -0,0 +1,20 @@
<pool type='rbd' xmlns:rbd='http://libvirt.org/schemas/storagepool/source/rbd/1.0'>
<name>ceph</name>
<uuid>47c1faee-0207-e741-f5ae-d9b019b98fe2</uuid>
<capacity unit='bytes'>0</capacity>
<allocation unit='bytes'>0</allocation>
<available unit='bytes'>0</available>
<source>
<host name='localhost' port='6789'/>
<host name='localhost' port='6790'/>
<name>rbd</name>
<auth type='ceph' username='admin'>
<secret uuid='2ec115d7-3a88-3ceb-bc12-0ac909a6fd87'/>
</auth>
</source>
<rbd:config_opts>
<rbd:option name='client_mount_timeout' value='45'/>
<rbd:option name='rados_mon_op_timeout' value='10'/>
<rbd:option name='rados_osd_op_timeout' value='20'/>
</rbd:config_opts>
</pool>

View File

@ -106,6 +106,7 @@ mymain(void)
DO_TEST("pool-zfs"); DO_TEST("pool-zfs");
DO_TEST("pool-zfs-sourcedev"); DO_TEST("pool-zfs-sourcedev");
DO_TEST("pool-rbd"); DO_TEST("pool-rbd");
DO_TEST("pool-rbd-ns-configopts");
DO_TEST("pool-vstorage"); DO_TEST("pool-vstorage");
DO_TEST("pool-iscsi-direct-auth"); DO_TEST("pool-iscsi-direct-auth");
DO_TEST("pool-iscsi-direct"); DO_TEST("pool-iscsi-direct");