Fix checkmount error parsing in swift-recon

- swift-recon now handles parsing instances where 'mounted' key (in unmounted
  and disk_usage) is an error message instead of a bool.
- Add's checkmount exception handling to the recon umounted endpoint.
- Updates existing unittest to have ismount throw an error.
- Updates unittests to cover the corner cases

Change-Id: Id51d14a8b98de69faaac84b2b34b7404b7df69e9
This commit is contained in:
Florian Hines 2013-12-18 14:03:23 -06:00 committed by John Dickinson
parent c72c10a1fe
commit 62254e42c4
3 changed files with 50 additions and 15 deletions

View File

@ -242,20 +242,29 @@ class SwiftRecon(object):
:param hosts: set of hosts to check. in the format of: :param hosts: set of hosts to check. in the format of:
set([('127.0.0.1', 6020), ('127.0.0.2', 6030)]) set([('127.0.0.1', 6020), ('127.0.0.2', 6030)])
""" """
stats = {} unmounted = {}
errors = {}
recon = Scout("unmounted", self.verbose, self.suppress_errors, recon = Scout("unmounted", self.verbose, self.suppress_errors,
self.timeout) self.timeout)
print "[%s] Getting unmounted drives from %s hosts..." % \ print "[%s] Getting unmounted drives from %s hosts..." % \
(self._ptime(), len(hosts)) (self._ptime(), len(hosts))
for url, response, status in self.pool.imap(recon.scout, hosts): for url, response, status in self.pool.imap(recon.scout, hosts):
if status == 200: if status == 200:
stats[url] = [] unmounted[url] = []
errors[url] = []
for i in response: for i in response:
stats[url].append(i['device']) if not isinstance(i['mounted'], bool):
for host in stats: errors[url].append(i['device'])
else:
unmounted[url].append(i['device'])
for host in unmounted:
node = urlparse(host).netloc node = urlparse(host).netloc
for entry in stats[host]: for entry in unmounted[host]:
print "Not mounted: %s on %s" % (entry, node) print "Not mounted: %s on %s" % (entry, node)
for host in errors:
node = urlparse(host).netloc
for entry in errors[host]:
print "Device errors: %s on %s" % (entry, node)
print "=" * 79 print "=" * 79
def expirer_check(self, hosts): def expirer_check(self, hosts):
@ -655,7 +664,10 @@ class SwiftRecon(object):
if status == 200: if status == 200:
hostusage = [] hostusage = []
for entry in response: for entry in response:
if entry['mounted']: if not isinstance(entry['mounted'], bool):
print "-> %s/%s: Error: %s" % (url, entry['device'],
entry['mounted'])
elif entry['mounted']:
used = float(entry['used']) / float(entry['size']) \ used = float(entry['used']) / float(entry['size']) \
* 100.0 * 100.0
raw_total_used.append(entry['used']) raw_total_used.append(entry['used'])

View File

@ -191,9 +191,12 @@ class ReconMiddleware(object):
"""list unmounted (failed?) devices""" """list unmounted (failed?) devices"""
mountlist = [] mountlist = []
for entry in os.listdir(self.devices): for entry in os.listdir(self.devices):
mpoint = {'device': entry, try:
'mounted': check_mount(self.devices, entry)} mounted = check_mount(self.devices, entry)
if not mpoint['mounted']: except OSError as err:
mounted = str(err)
mpoint = {'device': entry, 'mounted': mounted}
if mpoint['mounted'] is not True:
mountlist.append(mpoint) mountlist.append(mpoint)
return mountlist return mountlist

View File

@ -101,6 +101,9 @@ class MockOS(object):
def fake_ismount(self, *args, **kwargs): def fake_ismount(self, *args, **kwargs):
self.ismount_calls.append((args, kwargs)) self.ismount_calls.append((args, kwargs))
if isinstance(self.ismount_output, Exception):
raise self.ismount_output
else:
return self.ismount_output return self.ismount_output
def fake_statvfs(self, *args, **kwargs): def fake_statvfs(self, *args, **kwargs):
@ -560,7 +563,6 @@ class TestReconSuccess(TestCase):
"quarantined": 0}}) "quarantined": 0}})
def test_get_unmounted(self): def test_get_unmounted(self):
unmounted_resp = [{'device': 'fakeone', 'mounted': False}, unmounted_resp = [{'device': 'fakeone', 'mounted': False},
{'device': 'faketwo', 'mounted': False}] {'device': 'faketwo', 'mounted': False}]
self.mockos.ls_output = ['fakeone', 'faketwo'] self.mockos.ls_output = ['fakeone', 'faketwo']
@ -569,6 +571,24 @@ class TestReconSuccess(TestCase):
self.assertEquals(self.mockos.listdir_calls, [(('/srv/node/',), {})]) self.assertEquals(self.mockos.listdir_calls, [(('/srv/node/',), {})])
self.assertEquals(rv, unmounted_resp) self.assertEquals(rv, unmounted_resp)
def test_get_unmounted_everything_normal(self):
unmounted_resp = []
self.mockos.ls_output = ['fakeone', 'faketwo']
self.mockos.ismount_output = True
rv = self.app.get_unmounted()
self.assertEquals(self.mockos.listdir_calls, [(('/srv/node/',), {})])
self.assertEquals(rv, unmounted_resp)
def test_get_unmounted_checkmount_fail(self):
unmounted_resp = [{'device': 'fakeone', 'mounted': 'brokendrive'}]
self.mockos.ls_output = ['fakeone']
self.mockos.ismount_output = OSError('brokendrive')
rv = self.app.get_unmounted()
self.assertEquals(self.mockos.listdir_calls, [(('/srv/node/',), {})])
self.assertEquals(self.mockos.ismount_calls,
[(('/srv/node/fakeone',), {})])
self.assertEquals(rv, unmounted_resp)
def test_no_get_unmounted(self): def test_no_get_unmounted(self):
def fake_checkmount_true(*args): def fake_checkmount_true(*args):
@ -601,9 +621,9 @@ class TestReconSuccess(TestCase):
def test_get_diskusage_checkmount_fail(self): def test_get_diskusage_checkmount_fail(self):
du_resp = [{'device': 'canhazdrive1', 'avail': '', du_resp = [{'device': 'canhazdrive1', 'avail': '',
'mounted': False, 'used': '', 'size': ''}] 'mounted': 'brokendrive', 'used': '', 'size': ''}]
self.mockos.ls_output = ['canhazdrive1'] self.mockos.ls_output = ['canhazdrive1']
self.mockos.ismount_output = False self.mockos.ismount_output = OSError('brokendrive')
rv = self.app.get_diskusage() rv = self.app.get_diskusage()
self.assertEquals(self.mockos.listdir_calls, [(('/srv/node/',), {})]) self.assertEquals(self.mockos.listdir_calls, [(('/srv/node/',), {})])
self.assertEquals(self.mockos.ismount_calls, self.assertEquals(self.mockos.ismount_calls,