Hello Ayal Baron, Timothy Asir, Saggi Mizrahi, Federico Simoncelli, Dan
Kenigsberg,
I'd like you to do a code review. Please visit
http://gerrit.ovirt.org/7951
to review the following change.
Change subject: [WIP] used gluster cli xml output
......................................................................
[WIP] used gluster cli xml output
Below verbs are using gluster cli xml output
glusterVolumesList
glusterVolumeCreate
glusterVolumeStart
glusterVolumeStop
glusterVolumeDelete
glusterVolumeSet
glusterVolumeReset
glusterVolumeAddBrick
glusterVolumeRemoveBrickForce
glusterHostAdd
glusterHostRemove
Change-Id: I364930675dcc433dfc0432a343fc66e91721e801
Signed-off-by: Bala.FA <[email protected]>
---
M tests/gluster_cli_tests.py
M vdsm/gluster/api.py
M vdsm/gluster/cli.py
3 files changed, 195 insertions(+), 179 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/51/7951/1
diff --git a/tests/gluster_cli_tests.py b/tests/gluster_cli_tests.py
index bb88918..e5fe1ce 100644
--- a/tests/gluster_cli_tests.py
+++ b/tests/gluster_cli_tests.py
@@ -39,41 +39,98 @@
raise SkipTest("vdsm-gluster not found")
def _parseVolumeInfo_empty_test(self):
- out = ['No volumes present']
- self.assertFalse(gcli._parseVolumeInfo(out))
+ out = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<cliOutput>
+ <opRet>0</opRet>
+ <opErrno>0</opErrno>
+ <opErrstr/>
+ <volInfo/>
+</cliOutput>
+"""
+ tree = etree.fromstring(out)
+ self.assertFalse(gcli._parseVolumeInfo(tree))
def _parseVolumeInfo_test(self):
- out = [' ',
- 'Volume Name: music',
- 'Type: Distribute',
- 'Volume ID: 1e7d2638-fb77-4325-94fd-3242650a013c',
- 'Status: Stopped',
- 'Number of Bricks: 2',
- 'Transport-type: tcp',
- 'Bricks:',
- 'Brick1: 192.168.122.167:/tmp/music-b1',
- 'Brick2: 192.168.122.167:/tmp/music-b2',
- 'Options Reconfigured:',
- 'auth.allow: *']
- volumeInfo = gcli._parseVolumeInfo(out)
- for volumeName in volumeInfo:
- if volumeName == 'music':
- self.assertEquals(volumeInfo['music']['volumeName'],
- volumeName)
- self.assertEquals(volumeInfo['music']['uuid'],
- '1e7d2638-fb77-4325-94fd-3242650a013c')
- self.assertEquals(volumeInfo['music']['volumeType'],
- 'DISTRIBUTE')
- self.assertEquals(volumeInfo['music']['volumeStatus'],
- 'STOPPED')
- self.assertEquals(volumeInfo['music']['transportType'],
- ['TCP'])
- self.assertEquals(volumeInfo['music']['bricks'],
- ['192.168.122.167:/tmp/music-b1',
- '192.168.122.167:/tmp/music-b2'])
- self.assertEquals(volumeInfo['music']['brickCount'], '2')
- self.assertEquals(volumeInfo['music']['options'],
- {'auth.allow': '*'})
+ out = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<cliOutput>
+ <opRet>0</opRet>
+ <opErrno>0</opErrno>
+ <opErrstr/>
+ <volInfo>
+ <volumes>
+ <volume>
+ <name>music</name>
+ <id>b3114c71-741b-4c6f-a39e-80384c4ea3cf</id>
+ <type>2</type>
+ <status>1</status>
+ <brickCount>2</brickCount>
+ <distCount>2</distCount>
+ <stripeCount>1</stripeCount>
+ <replicaCount>2</replicaCount>
+ <transport>0</transport>
+ <bricks>
+ <brick>192.168.122.2:/tmp/music-b1</brick>
+ <brick>192.168.122.2:/tmp/music-b2</brick>
+ </bricks>
+ <optCount>1</optCount>
+ <options>
+ <option>
+ <name>auth.allow</name>
+ <value>*</value>
+ </option>
+ </options>
+ </volume>
+ <volume>
+ <name>test1</name>
+ <id>2e562614-00ad-4acb-a630-4429049a9818</id>
+ <type>0</type>
+ <status>2</status>
+ <brickCount>2</brickCount>
+ <distCount>1</distCount>
+ <stripeCount>1</stripeCount>
+ <replicaCount>1</replicaCount>
+ <transport>1</transport>
+ <bricks>
+ <brick>192.168.122.2:/tmp/test1-b1</brick>
+ <brick>192.168.122.2:/tmp/test1-b2</brick>
+ </bricks>
+ <optCount>0</optCount>
+ <options/>
+ </volume>
+ <count>2</count>
+ </volumes>
+ </volInfo>
+</cliOutput>
+"""
+ tree = etree.fromstring(out)
+ oVolumeInfo = {'music':
+ {'brickCount': '2',
+ 'bricks': ['192.168.122.2:/tmp/music-b1',
+ '192.168.122.2:/tmp/music-b2'],
+ 'distCount': '2',
+ 'options': {'auth.allow': '*'},
+ 'replicaCount': '2',
+ 'stripeCount': '1',
+ 'transportType': [gcli.TransportType.TCP],
+ 'uuid': 'b3114c71-741b-4c6f-a39e-80384c4ea3cf',
+ 'volumeName': 'music',
+ 'volumeStatus': gcli.VolumeStatus.ONLINE,
+ 'volumeType': '2'},
+ 'test1':
+ {'brickCount': '2',
+ 'bricks': ['192.168.122.2:/tmp/test1-b1',
+ '192.168.122.2:/tmp/test1-b2'],
+ 'distCount': '1',
+ 'options': {},
+ 'replicaCount': '1',
+ 'stripeCount': '1',
+ 'transportType': [gcli.TransportType.RDMA],
+ 'uuid': '2e562614-00ad-4acb-a630-4429049a9818',
+ 'volumeName': 'test1',
+ 'volumeStatus': gcli.VolumeStatus.OFFLINE,
+ 'volumeType': '0'}}
+ volumeInfo = gcli._parseVolumeInfo(tree)
+ self.assertEquals(volumeInfo, oVolumeInfo)
def test_parseVolumeInfo(self):
self._parseVolumeInfo_empty_test()
diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index ba1f374..3c1bc58 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -42,11 +42,6 @@
return wrapper
-class VolumeStatus():
- ONLINE = 'ONLINE'
- OFFLINE = 'OFFLINE'
-
-
class GlusterApi(object):
"""
The gluster interface of vdsm.
@@ -120,35 +115,14 @@
@exportAsVerb
def volumesList(self, volumeName=None, options=None):
- """
- Returns:
- {'status' : {'code': CODE, 'message': MESSAGE},
- 'volumes': {VOLUMENAME: {'brickCount': BRICKCOUNT,
- 'bricks': [BRICK1, BRICK2, ...],
- 'options': {OPTION: VALUE, ...},
- 'transportType': [TCP, RDMA, ...],
- 'uuid': UUID,
- 'volumeName': NAME,
- 'volumeStatus': STATUS,
- 'volumeType': TYPE}, ...}}
- """
- volumeInfoDict = self.svdsmProxy.glusterVolumeInfo(volumeName)
- for name, info in volumeInfoDict.iteritems():
- info["volumeType"] = info["volumeType"].replace("-", "_")
- if info["volumeStatus"] == "STARTED":
- info["volumeStatus"] = VolumeStatus.ONLINE
- else:
- info["volumeStatus"] = VolumeStatus.OFFLINE
- return {'volumes': volumeInfoDict}
+ return {'volumes': self.svdsmProxy.glusterVolumeInfo(volumeName)}
@exportAsVerb
def volumeCreate(self, volumeName, brickList, replicaCount=0,
stripeCount=0, transportList=[], options=None):
- self.svdsmProxy.glusterVolumeCreate(volumeName, brickList,
- replicaCount, stripeCount,
- transportList)
- volumeList = self.svdsmProxy.glusterVolumeInfo()
- return {'uuid': volumeList[volumeName]['uuid']}
+ return self.svdsmProxy.glusterVolumeCreate(volumeName, brickList,
+ replicaCount, stripeCount,
+ transportList)
@exportAsVerb
def volumeStart(self, volumeName, force=False, options=None):
diff --git a/vdsm/gluster/cli.py b/vdsm/gluster/cli.py
index e31c3f4..2ead7c9 100644
--- a/vdsm/gluster/cli.py
+++ b/vdsm/gluster/cli.py
@@ -18,7 +18,6 @@
# Refer to the README and COPYING files for full details of the license
#
-import re
import xml.etree.cElementTree as etree
from functools import wraps
@@ -30,7 +29,6 @@
_glusterCommandPath = utils.CommandPath("gluster",
"/usr/sbin/gluster",
)
-_brickCountRegEx = re.compile('(\d+) x (\d+) = (\d+)')
def _getGlusterVolCmd():
@@ -74,6 +72,16 @@
RUNNING = 'RUNNING'
FAILED = 'FAILED'
COMPLETED = 'COMPLETED'
+
+
+class VolumeStatus:
+ ONLINE = 'ONLINE'
+ OFFLINE = 'OFFLINE'
+
+
+class TransportType:
+ TCP = 'TCP'
+ RDMA = 'RDMA'
def _execGluster(cmd):
@@ -354,76 +362,47 @@
raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
-def _parseVolumeInfo(out):
- if not out[0].strip():
- del out[0]
- if out[-1].strip():
- out += [""]
-
- if out[0].strip().upper() == "NO VOLUMES PRESENT":
- return {}
-
- volumeInfoDict = {}
- volumeInfo = {}
- volumeName = None
- brickList = []
- volumeOptions = {}
- for line in out:
- line = line.strip()
- if not line:
- if volumeName and volumeInfo:
- volumeInfo["bricks"] = brickList
- volumeInfo["options"] = volumeOptions
- volumeInfoDict[volumeName] = volumeInfo
- volumeInfo = {}
- volumeName = None
- brickList = []
- volumeOptions = {}
- continue
-
- tokens = line.split(":", 1)
- key = tokens[0].strip().upper()
- if key == "BRICKS":
- continue
- elif key == "OPTIONS RECONFIGURED":
- continue
- elif key == "VOLUME NAME":
- volumeName = tokens[1].strip()
- volumeInfo["volumeName"] = volumeName
- elif key == "VOLUME ID":
- volumeInfo["uuid"] = tokens[1].strip()
- elif key == "TYPE":
- volumeInfo["volumeType"] = tokens[1].strip().upper()
- elif key == "STATUS":
- volumeInfo["volumeStatus"] = tokens[1].strip().upper()
- elif key == "TRANSPORT-TYPE":
- volumeInfo["transportType"] = tokens[1].strip().upper().split(',')
- elif key.startswith("BRICK"):
- brickList.append(tokens[1].strip())
- elif key == "NUMBER OF BRICKS":
- volumeInfo["brickCount"] = tokens[1].strip()
+def _parseVolumeInfo(tree):
+ """
+ {VOLUMENAME: {'brickCount': BRICKCOUNT,
+ 'bricks': [BRICK1, BRICK2, ...],
+ 'options': {OPTION: VALUE, ...},
+ 'transportType': [TCP,RDMA, ...],
+ 'uuid': UUID,
+ 'volumeName': NAME,
+ 'volumeStatus': STATUS,
+ 'volumeType': TYPE}, ...}
+ """
+ volumes = {}
+ for el in tree.findall('volInfo/volumes/volume'):
+ value = {}
+ value['volumeName'] = el.find('name').text
+ value['uuid'] = el.find('id').text
+ value['volumeType'] = el.find('type').text
+ status = el.find('status').text
+ if status == '1':
+ value["volumeStatus"] = VolumeStatus.ONLINE
else:
- volumeOptions[tokens[0].strip()] = tokens[1].strip()
-
- for volumeName, volumeInfo in volumeInfoDict.iteritems():
- if volumeInfo["volumeType"] == "REPLICATE":
- volumeInfo["replicaCount"] = volumeInfo["brickCount"]
- elif volumeInfo["volumeType"] == "STRIPE":
- volumeInfo["stripeCount"] = volumeInfo["brickCount"]
- elif volumeInfo["volumeType"] == "DISTRIBUTED-REPLICATE":
- m = _brickCountRegEx.match(volumeInfo["brickCount"])
- if m:
- volumeInfo["replicaCount"] = m.groups()[1]
- else:
- volumeInfo["replicaCount"] = ""
-
- elif volumeInfo["volumeType"] == "DISTRIBUTED-STRIPE":
- m = _brickCountRegEx.match(volumeInfo["brickCount"])
- if m:
- volumeInfo["stripeCount"] = m.groups()[1]
- else:
- volumeInfo["stripeCount"] = ""
- return volumeInfoDict
+ value["volumeStatus"] = VolumeStatus.OFFLINE
+ value['brickCount'] = el.find('brickCount').text
+ value['distCount'] = el.find('distCount').text
+ value['stripeCount'] = el.find('stripeCount').text
+ value['replicaCount'] = el.find('replicaCount').text
+ transportType = el.find('transport').text
+ if transportType == '0':
+ value['transportType'] = [TransportType.TCP]
+ elif transportType == '1':
+ value['transportType'] = [TransportType.RDMA]
+ else:
+ value['transportType'] = [TransportType.TCP, TransportType.RDMA]
+ value['bricks'] = []
+ value['options'] = {}
+ for b in el.findall('bricks/brick'):
+ value['bricks'].append(b.text)
+ for o in el.findall('options/option'):
+ value['options'][o.find('name').text] = o.find('value').text
+ volumes[value['volumeName']] = value
+ return volumes
@exportToSuperVdsm
@@ -442,11 +421,14 @@
command = _getGlusterVolCmd() + ["info"]
if volumeName:
command.append(volumeName)
- rc, out, err = _execGluster(command)
- if rc:
- raise ge.GlusterVolumesListFailedException(rc, out, err)
- else:
- return _parseVolumeInfo(out)
+ try:
+ xmltree = _execGlusterXml(command)
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterVolumesListFailedException(rc=e.rc, err=e.err)
+ try:
+ return _parseVolumeInfo(xmltree)
+ except (etree.ParseError, AttributeError, ValueError):
+ raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
@exportToSuperVdsm
@@ -460,12 +442,14 @@
if transportList:
command += ["transport", ','.join(transportList)]
command += brickList
-
- rc, out, err = _execGluster(command)
- if rc:
- raise ge.GlusterVolumeCreateFailedException(rc, out, err)
- else:
- return True
+ try:
+ xmltree = _execGlusterXml(command)
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterVolumeCreateFailedException(rc=e.rc, err=e.err)
+ try:
+ return {'uuid': xmltree.find('id').text}
+ except (etree.ParseError, AttributeError, ValueError):
+ raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
@exportToSuperVdsm
@@ -473,11 +457,11 @@
command = _getGlusterVolCmd() + ["start", volumeName]
if force:
command.append('force')
- rc, out, err = _execGluster(command)
- if rc:
- raise ge.GlusterVolumeStartFailedException(rc, out, err)
- else:
+ try:
+ _execGlusterXml(command)
return True
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterVolumeStartFailedException(rc=e.rc, err=e.err)
@exportToSuperVdsm
@@ -485,30 +469,31 @@
command = _getGlusterVolCmd() + ["stop", volumeName]
if force:
command.append('force')
- rc, out, err = _execGluster(command)
- if rc:
- raise ge.GlusterVolumeStopFailedException(rc, out, err)
- else:
+ try:
+ _execGlusterXml(command)
return True
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterVolumeStopFailedException(rc=e.rc, err=e.err)
@exportToSuperVdsm
def volumeDelete(volumeName):
- rc, out, err = _execGluster(_getGlusterVolCmd() + ["delete", volumeName])
- if rc:
- raise ge.GlusterVolumeDeleteFailedException(rc, out, err)
- else:
+ command = _getGlusterVolCmd() + ["delete", volumeName]
+ try:
+ _execGlusterXml(command)
return True
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterVolumeDeleteFailedException(rc=e.rc, err=e.err)
@exportToSuperVdsm
def volumeSet(volumeName, option, value):
- rc, out, err = _execGluster(_getGlusterVolCmd() + ["set", volumeName,
- option, value])
- if rc:
- raise ge.GlusterVolumeSetFailedException(rc, out, err)
- else:
+ command = _getGlusterVolCmd() + ["set", volumeName, option, value]
+ try:
+ _execGlusterXml(command)
return True
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterVolumeSetFailedException(rc=e.rc, err=e.err)
def _parseVolumeSetHelpXml(out):
@@ -538,11 +523,11 @@
command.append(option)
if force:
command.append('force')
- rc, out, err = _execGluster(command)
- if rc:
- raise ge.GlusterVolumeResetFailedException(rc, out, err)
- else:
+ try:
+ _execGlusterXml(command)
return True
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterVolumeResetFailedException(rc=e.rc, err=e.err)
@exportToSuperVdsm
@@ -554,12 +539,11 @@
if replicaCount:
command += ["replica", "%s" % replicaCount]
command += brickList
-
- rc, out, err = _execGluster(command)
- if rc:
- raise ge.GlusterVolumeBrickAddFailedException(rc, out, err)
- else:
+ try:
+ _execGlusterXml(command)
return True
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterVolumeBrickAddFailedException(rc=e.rc, err=e.err)
@exportToSuperVdsm
@@ -820,11 +804,12 @@
@exportToSuperVdsm
def peerProbe(hostName):
- rc, out, err = _execGluster(_getGlusterPeerCmd() + ["probe", hostName])
- if rc:
- raise ge.GlusterHostAddFailedException(rc, out, err)
- else:
+ command = _getGlusterPeerCmd() + ["probe", hostName]
+ try:
+ _execGlusterXml(command)
return True
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterHostAddFailedException(rc=e.rc, err=e.err)
@exportToSuperVdsm
@@ -832,11 +817,11 @@
command = _getGlusterPeerCmd() + ["detach", hostName]
if force:
command.append('force')
- rc, out, err = _execGluster(command)
- if rc:
- raise ge.GlusterHostRemoveFailedException(rc, out, err)
- else:
+ try:
+ _execGlusterXml(command)
return True
+ except ge.GlusterCmdFailedException, e:
+ raise ge.GlusterHostRemoveFailedException(rc=e.rc, err=e.err)
def _parsePeerStatus(tree, gHostName, gUuid, gStatus):
--
To view, visit http://gerrit.ovirt.org/7951
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I364930675dcc433dfc0432a343fc66e91721e801
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Bala.FA <[email protected]>
Gerrit-Reviewer: Ayal Baron <[email protected]>
Gerrit-Reviewer: Dan Kenigsberg <[email protected]>
Gerrit-Reviewer: Federico Simoncelli <[email protected]>
Gerrit-Reviewer: Saggi Mizrahi <[email protected]>
Gerrit-Reviewer: Timothy Asir <[email protected]>
_______________________________________________
vdsm-patches mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches