glusterfs: handle new cli XML format
Change http://review.gluster.org/14931, debuting in GlusterFS 3.7.14 has changed the XML output emitted by the gluster command line interface. Here we implement parsing for the new variant as well. Change-Id: Ia9f340f1d56c95d5ebf5577df6aae9d708a026c0 Closes-Bug: 1609858
This commit is contained in:
parent
a7dc61e425
commit
58be1ef71a
@ -61,14 +61,18 @@ def _check_volume_presence(f):
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def volxml_get(xmlout, path, *default):
|
def volxml_get(xmlout, *paths, **kwargs):
|
||||||
"""Extract a value by a path from XML."""
|
"""Attempt to extract a value by a set of Xpaths from XML."""
|
||||||
value = xmlout.find(path)
|
for path in paths:
|
||||||
|
value = xmlout.find(path)
|
||||||
|
if value is not None:
|
||||||
|
break
|
||||||
if value is None:
|
if value is None:
|
||||||
if default:
|
if 'default' in kwargs:
|
||||||
return default[0]
|
return kwargs['default']
|
||||||
raise exception.InvalidShare(
|
raise exception.InvalidShare(
|
||||||
_('Xpath %s not found in volume query response XML') % path)
|
_("Volume query response XML has no value for any of "
|
||||||
|
"the following Xpaths: %s") % ", ".join(paths))
|
||||||
return value.text
|
return value.text
|
||||||
|
|
||||||
|
|
||||||
@ -225,7 +229,7 @@ class GlusterManager(object):
|
|||||||
) % {'volume': self.volume, 'command': command})
|
) % {'volume': self.volume, 'command': command})
|
||||||
if list(six.itervalues(ret)) != [0, 0]:
|
if list(six.itervalues(ret)) != [0, 0]:
|
||||||
errdct = {'volume': self.volume, 'command': commandstr,
|
errdct = {'volume': self.volume, 'command': commandstr,
|
||||||
'opErrstr': volxml_get(xmlout, 'opErrstr', None)}
|
'opErrstr': volxml_get(xmlout, 'opErrstr', default=None)}
|
||||||
errdct.update(ret)
|
errdct.update(ret)
|
||||||
raise exception.InvalidShare(_(
|
raise exception.InvalidShare(_(
|
||||||
'GlusterFS command %(command)s on volume %(volume)s got '
|
'GlusterFS command %(command)s on volume %(volume)s got '
|
||||||
@ -289,7 +293,10 @@ class GlusterManager(object):
|
|||||||
return self._get_vol_option_via_info(option)
|
return self._get_vol_option_via_info(option)
|
||||||
|
|
||||||
self.xml_response_check(optxml, args[1:], './volGetopts/count')
|
self.xml_response_check(optxml, args[1:], './volGetopts/count')
|
||||||
return volxml_get(optxml, './volGetopts/Value')
|
# the Xpath has changed from first to second as of GlusterFS
|
||||||
|
# 3.7.14 (see http://review.gluster.org/14931).
|
||||||
|
return volxml_get(optxml, './volGetopts/Value',
|
||||||
|
'./volGetopts/Opt/Value')
|
||||||
|
|
||||||
def get_vol_option(self, option, boolean=False):
|
def get_vol_option(self, option, boolean=False):
|
||||||
"""Get the value of an option set on a GlusterFS volume."""
|
"""Get the value of an option set on a GlusterFS volume."""
|
||||||
|
@ -542,7 +542,7 @@ class GlusterfsVolumeMappedLayout(layout.GlusterfsShareLayoutBase):
|
|||||||
outxml = etree.fromstring(out)
|
outxml = etree.fromstring(out)
|
||||||
opret = int(common.volxml_get(outxml, 'opRet'))
|
opret = int(common.volxml_get(outxml, 'opRet'))
|
||||||
operrno = int(common.volxml_get(outxml, 'opErrno'))
|
operrno = int(common.volxml_get(outxml, 'opErrno'))
|
||||||
operrstr = common.volxml_get(outxml, 'opErrstr', None)
|
operrstr = common.volxml_get(outxml, 'opErrstr', default=None)
|
||||||
|
|
||||||
if opret == -1:
|
if opret == -1:
|
||||||
vers = self.glusterfs_versions[gluster_mgr.host_access]
|
vers = self.glusterfs_versions[gluster_mgr.host_access]
|
||||||
|
@ -98,10 +98,20 @@ class GlusterManagerTestCase(test.TestCase):
|
|||||||
xmlout = mock.Mock()
|
xmlout = mock.Mock()
|
||||||
xmlout.find = mock.Mock(return_value=None)
|
xmlout.find = mock.Mock(return_value=None)
|
||||||
|
|
||||||
ret = common.volxml_get(xmlout, 'some/path', default)
|
ret = common.volxml_get(xmlout, 'some/path', default=default)
|
||||||
|
|
||||||
self.assertEqual(default, ret)
|
self.assertEqual(default, ret)
|
||||||
|
|
||||||
|
def test_volxml_get_multiple(self):
|
||||||
|
xmlout = mock.Mock()
|
||||||
|
value = mock.Mock()
|
||||||
|
value.text = 'foobar'
|
||||||
|
xmlout.find = mock.Mock(side_effect=(None, value))
|
||||||
|
|
||||||
|
ret = common.volxml_get(xmlout, 'some/path', 'better/path')
|
||||||
|
|
||||||
|
self.assertEqual('foobar', ret)
|
||||||
|
|
||||||
def test_volxml_get_notfound(self):
|
def test_volxml_get_notfound(self):
|
||||||
xmlout = mock.Mock()
|
xmlout = mock.Mock()
|
||||||
xmlout.find = mock.Mock(return_value=None)
|
xmlout.find = mock.Mock(return_value=None)
|
||||||
@ -385,11 +395,11 @@ class GlusterManagerTestCase(test.TestCase):
|
|||||||
{'opRet': '0', 'opErrno': '0', 'some/count': '2'})
|
{'opRet': '0', 'opErrno': '0', 'some/count': '2'})
|
||||||
def test_xml_response_check_invalid(self, fdict):
|
def test_xml_response_check_invalid(self, fdict):
|
||||||
|
|
||||||
def vxget(x, e, *a):
|
def vxget(x, *e, **kw):
|
||||||
if a:
|
if kw:
|
||||||
return fdict.get(e, a[0])
|
return fdict.get(e[0], kw['default'])
|
||||||
else:
|
else:
|
||||||
return fdict[e]
|
return fdict[e[0]]
|
||||||
|
|
||||||
xtree = mock.Mock()
|
xtree = mock.Mock()
|
||||||
command = ['volume', 'command', 'fake']
|
command = ['volume', 'command', 'fake']
|
||||||
@ -557,7 +567,8 @@ class GlusterManagerTestCase(test.TestCase):
|
|||||||
self._gluster_manager.gluster_call.assert_called_once_with(
|
self._gluster_manager.gluster_call.assert_called_once_with(
|
||||||
*args, check_exit_code=False)
|
*args, check_exit_code=False)
|
||||||
|
|
||||||
def test_get_vol_regular_option(self):
|
@ddt.data({'start': "", 'end': ""}, {'start': "<Opt>", 'end': "</Opt>"})
|
||||||
|
def test_get_vol_regular_option(self, extratag):
|
||||||
|
|
||||||
def xml_output(*ignore_args, **ignore_kwargs):
|
def xml_output(*ignore_args, **ignore_kwargs):
|
||||||
return """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
return """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
@ -567,10 +578,12 @@ class GlusterManagerTestCase(test.TestCase):
|
|||||||
<opErrstr/>
|
<opErrstr/>
|
||||||
<volGetopts>
|
<volGetopts>
|
||||||
<count>1</count>
|
<count>1</count>
|
||||||
|
%(start)s
|
||||||
<Option>nfs.export-dir</Option>
|
<Option>nfs.export-dir</Option>
|
||||||
<Value>/foo(10.0.0.1|10.0.0.2),/bar(10.0.0.1)</Value>
|
<Value>/foo(10.0.0.1|10.0.0.2),/bar(10.0.0.1)</Value>
|
||||||
|
%(end)s
|
||||||
</volGetopts>
|
</volGetopts>
|
||||||
</cliOutput>""", ''
|
</cliOutput>""" % extratag, ''
|
||||||
|
|
||||||
args = ('--xml', 'volume', 'get', self._gluster_manager.volume,
|
args = ('--xml', 'volume', 'get', self._gluster_manager.volume,
|
||||||
NFS_EXPORT_DIR)
|
NFS_EXPORT_DIR)
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- GlusterFS drivers now handle the volume
|
||||||
|
option XML schema of GlusterFS >= 3.7.14.
|
Loading…
Reference in New Issue
Block a user