diff options
author | Sahina Bose <sabose@redhat.com> | 2015-09-29 12:19:04 +0530 |
---|---|---|
committer | Sahina Bose <sabose@redhat.com> | 2016-03-24 00:10:09 -0700 |
commit | 57c6902d0dd84950adaa21cf6f649e679a913b37 (patch) | |
tree | 59daae483ddf33aeb8db0d195caba75e6b2d6dac | |
parent | 92af01d26b460381835163113b3750573bd29824 (diff) |
Added CLI to parse heal info and provide
json output
changed parsing of heal info to match the enhanced
output patch - http://review.gluster.org/13231
Renamed VolumeSplitBrainStatus enum to generic VolumeHealInfoStatus
BUG: 1267586
Change-Id: I948d00d0198894a9a670e72b311ab86c83af4b23
Signed-off-by: Sahina Bose <sabose@redhat.com>
Reviewed-on: http://review.gluster.org/12260
Reviewed-by: Ramesh N <rnachimu@redhat.com>
-rwxr-xr-x | glusternagios/glustercli.py | 56 | ||||
-rw-r--r-- | tests/test_glustercli.py | 112 |
2 files changed, 142 insertions, 26 deletions
diff --git a/glusternagios/glustercli.py b/glusternagios/glustercli.py index 19469c1..af20676 100755 --- a/glusternagios/glustercli.py +++ b/glusternagios/glustercli.py @@ -94,10 +94,10 @@ class VolumeQuotaStatus: HARD_LIMIT_EXCEEDED = 'HARD_LIMIT_EXCEEDED' -class VolumeSplitBrainStatus: +class VolumeHealInfoStatus: NOTAPPLICABLE = 'NA' OK = 'OK' - SPLITBRAIN = 'SPLITBRAIN' + ENTRIESFOUND = 'ENTRIESFOUND' class GeoRepStatus: @@ -501,17 +501,24 @@ def _parseVolumeQuotaStatus(out, isDisabled=False): def _parseVolumeSelfHealInfo(out): value = {} - splitbrainentries = 0 + unsyncedentries = 0 + undergoingheal = 0 for line in out: if line.startswith('Number of entries'): - entries = int(line.split(':')[1]) + try: + entries = int(line.split(':')[1]) + except: + entries = 0 if entries > 0: - splitbrainentries += entries - if splitbrainentries > 0: - value['status'] = VolumeSplitBrainStatus.SPLITBRAIN + unsyncedentries += entries + if line.find('undergoing heal') > -1: + undergoingheal += 1 + if unsyncedentries > 0: + value['status'] = VolumeHealInfoStatus.ENTRIESFOUND else: - value['status'] = VolumeSplitBrainStatus.OK - value['unsyncedentries'] = splitbrainentries + value['status'] = VolumeHealInfoStatus.OK + value['unsyncedentries'] = unsyncedentries + value['undergoingheal'] = undergoingheal return value @@ -622,7 +629,8 @@ def volumeHealStatus(volumeName, remoteServer=None): * VolumeName Returns: {VOLUMENAME: {'status': SELFHEALSTATUS, - 'unsyncedentries': ENTRYCOUNT}} + 'unsyncedentries': ENTRYCOUNT + 'undergoingheal': COUNT}} """ command = _getGlusterVolCmd() + ["heal", volumeName, "info"] return _volumeHealCommandOutput(volumeName, command, remoteServer) @@ -634,7 +642,8 @@ def volumeHealSplitBrainStatus(volumeName, remoteServer=None): * VolumeName Returns: {VOLUMENAME: {'status': SELFHEALSTATUS, - 'unsyncedentries': ENTRYCOUNT}} + 'unsyncedentries': ENTRYCOUNT + 'undergoingheal': COUNT}} """ command = _getGlusterVolCmd() + ["heal", volumeName, "info", "split-brain"] return _volumeHealCommandOutput(volumeName, command, remoteServer) @@ -646,25 +655,28 @@ def _volumeHealCommandOutput(volumeName, command, remoteServer=None): * VolumeName Returns: {VOLUMENAME: {'status': SELFHEALSTATUS, - 'unsyncedentries': ENTRYCOUNT}} + 'unsyncedentries': ENTRYCOUNT + 'undergoingheal': COUNT}} """ if remoteServer: command += ['--remote-host=%s' % remoteServer] - rc, out, err = _execGluster(command) + volumes = volumeInfo(volumeName, remoteServer) volume = {} value = {} - if rc == 0: - value = _parseVolumeSelfHealInfo(out) - volume[volumeName] = value - return volume - else: - if len(err) > 0 and err[0].find("is not of type replicate") > -1: - value['status'] = VolumeSplitBrainStatus.NOTAPPLICABLE - value['unsyncedentries'] = 0 + if "REPLICATE" in volumes[volumeName]["volumeType"]: + rc, out, err = _execGluster(command) + if rc == 0: + value = _parseVolumeSelfHealInfo(out) volume[volumeName] = value return volume - raise GlusterCmdFailedException(rc=rc, out=out, err=err) + raise GlusterCmdFailedException(rc=rc, out=out, err=err) + else: + value['status'] = VolumeHealInfoStatus.NOTAPPLICABLE + value['undergoingheal'] = 0 + value['unsyncedentries'] = 0 + volume[volumeName] = value + return volume def volumeQuotaStatus(volumeName, remoteServer=None): diff --git a/tests/test_glustercli.py b/tests/test_glustercli.py index d9ef1ab..d770b92 100644 --- a/tests/test_glustercli.py +++ b/tests/test_glustercli.py @@ -29,6 +29,8 @@ class GlusterCliTests(TestCaseBase): def _parseVolumeInfo_empty_test(self): out = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?> + + <cliOutput> <opRet>0</opRet> <opErrno>0</opErrno> @@ -1114,13 +1116,23 @@ class GlusterCliTests(TestCaseBase): @mock.patch('glusternagios.utils.execCmd') @mock.patch('glusternagios.glustercli._getGlusterVolCmd') - def test_getVolumeHealSplitBrainStatusNonRepl(self, mock_glusterVolCmd, + @mock.patch('glusternagios.glustercli.volumeInfo') + def test_getVolumeHealSplitBrainStatusNonRepl(self, + mock_volumeInfo, + mock_glusterVolCmd, mock_execCmd,): mock_glusterVolCmd.return_value = ["gluster", "volume"] + mock_volumeInfo.return_value = {'test-vol': + {'volumeType': 'DISTRIBUTE', + 'replicaCount': 1, + 'brickCount': 2 + } + } mock_execCmd.return_value = 2, None, ["Volume test-vol is not " "of type replicate"] expectedOut = {'test-vol': - {'status': gcli.VolumeSplitBrainStatus.NOTAPPLICABLE, + {'status': gcli.VolumeHealInfoStatus.NOTAPPLICABLE, + 'undergoingheal': 0, 'unsyncedentries': 0}} status = gcli.volumeHealSplitBrainStatus("test-vol") print(status) @@ -1128,19 +1140,79 @@ class GlusterCliTests(TestCaseBase): @mock.patch('glusternagios.utils.execCmd') @mock.patch('glusternagios.glustercli._getGlusterVolCmd') - def test_getVolumeHealSplitBrainStatus(self, mock_glusterVolCmd, + @mock.patch('glusternagios.glustercli.volumeInfo') + def test_getVolumeHealSplitBrainStatus(self, + mock_volumeInfo, + mock_glusterVolCmd, mock_execCmd,): mock_glusterVolCmd.return_value = ["gluster", "volume"] + mock_volumeInfo.return_value = {'test-vol': + {'volumeType': 'REPLICATE', + 'replicaCount': 2, + 'brickCount': 2 + } + } mock_execCmd.return_value = (0, self.__getGlusterSelfHealInfoResult(), None) expectedOut = {'test-vol': - {'status': gcli.VolumeSplitBrainStatus.SPLITBRAIN, + {'status': gcli.VolumeHealInfoStatus.ENTRIESFOUND, + 'undergoingheal': 0, 'unsyncedentries': 10}} status = gcli.volumeHealSplitBrainStatus("test-vol") print(status) self.assertEquals(status, expectedOut) + @mock.patch('glusternagios.utils.execCmd') + @mock.patch('glusternagios.glustercli._getGlusterVolCmd') + @mock.patch('glusternagios.glustercli.volumeInfo') + def test_getVolumeHealInfoUndergoingStatus(self, + mock_volumeInfo, + mock_glusterVolCmd, + mock_execCmd,): + mock_glusterVolCmd.return_value = ["gluster", "volume"] + mock_volumeInfo.return_value = {'test-vol': + {'volumeType': 'REPLICATE', + 'replicaCount': 2, + 'brickCount': 2 + } + } + mock_execCmd.return_value = (0, + self.__getGlusterSelfHealInfoUndergoingResult(), + None) + expectedOut = {'test-vol': + {'status': gcli.VolumeHealInfoStatus.ENTRIESFOUND, + 'undergoingheal': 1, + 'unsyncedentries': 10}} + status = gcli.volumeHealSplitBrainStatus("test-vol") + print(status) + self.assertEquals(status, expectedOut) + + @mock.patch('glusternagios.utils.execCmd') + @mock.patch('glusternagios.glustercli._getGlusterVolCmd') + @mock.patch('glusternagios.glustercli.volumeInfo') + def test_getVolumeHealSplitBrainStatusNoBrick(self, + mock_volumeInfo, + mock_glusterVolCmd, + mock_execCmd,): + mock_glusterVolCmd.return_value = ["gluster", "volume"] + mock_volumeInfo.return_value = {'test-vol': + {'volumeType': 'REPLICATE', + 'replicaCount': 2, + 'brickCount': 2 + } + } + mock_execCmd.return_value = (0, + self.__getGlusterSelfHealInfoResultBrickDown(), + None) + expectedOut = {'test-vol': + {'status': gcli.VolumeHealInfoStatus.OK, + 'undergoingheal': 0, + 'unsyncedentries': 0}} + status = gcli.volumeHealSplitBrainStatus("test-vol") + print(status) + self.assertEquals(status, expectedOut) + @mock.patch('glusternagios.glustercli._getGlusterVolCmd') @mock.patch('glusternagios.glustercli.volumeInfo') def test_getVolumeGeoRepStatus(self, @@ -1272,6 +1344,38 @@ class GlusterCliTests(TestCaseBase): "/dir.10/file.2", "/dir.7/file.4"] + def __getGlusterSelfHealInfoUndergoingResult(self): + return ["Gathering list of entries to be healed " + "on volume rep has been successful", + "", + "Brick node2:/bricks/b3", + "Status: Brick is Not connected", + "Number of entries in split-brain: NA" + "", + "Brick node1:/bricks/b3", + "Number of entries in split-brain: 10", + "/dir.7/file.5 - Possibly undergoing heal", + "/dir.8/file.3", + "/dir.9/file.5", + "/dir.2/file.4", + "/dir.9/file.4", + "/dir.4/file.1", + "/file.4", + "/dir.7/file.2", + "/dir.10/file.2", + "/dir.7/file.4"] + + def __getGlusterSelfHealInfoResultBrickDown(self): + return ["Gathering list of entries to be healed " + "on volume rep has been successful", + "", + "Brick node2:/bricks/b3", + "Status: Brick is Not connected", + "Number of entries in split-brain: 0" + "", + "Brick node1:/bricks/b3", + "Number of entries in split-brain: -"] + def __getGlusterGeoRepStatusResult(self): return """<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <cliOutput> |