Merge "Ring checker in swift-recon"
This commit is contained in:
commit
41058ba809
@ -109,6 +109,34 @@ class Scout(object):
|
|||||||
url, content, status = self.scout_host(base_url, self.recon_type)
|
url, content, status = self.scout_host(base_url, self.recon_type)
|
||||||
return url, content, status
|
return url, content, status
|
||||||
|
|
||||||
|
def scout_server_type(self, host):
|
||||||
|
"""
|
||||||
|
Obtain Server header by calling OPTIONS.
|
||||||
|
|
||||||
|
:param host: host to check
|
||||||
|
:returns: Server type, status
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
url = "http://%s:%s/" % (host[0], host[1])
|
||||||
|
req = urllib2.Request(url)
|
||||||
|
req.get_method = lambda: 'OPTIONS'
|
||||||
|
conn = urllib2.urlopen(req)
|
||||||
|
header = conn.info().getheader('Server')
|
||||||
|
server_header = header.split('/')
|
||||||
|
content = server_header[0]
|
||||||
|
status = 200
|
||||||
|
except urllib2.HTTPError as err:
|
||||||
|
if not self.suppress_errors or self.verbose:
|
||||||
|
print("-> %s: %s" % (url, err))
|
||||||
|
content = err
|
||||||
|
status = err.code
|
||||||
|
except urllib2.URLError as err:
|
||||||
|
if not self.suppress_errors or self.verbose:
|
||||||
|
print("-> %s: %s" % (url, err))
|
||||||
|
content = err
|
||||||
|
status = -1
|
||||||
|
return url, content, status
|
||||||
|
|
||||||
|
|
||||||
class SwiftRecon(object):
|
class SwiftRecon(object):
|
||||||
"""
|
"""
|
||||||
@ -334,6 +362,29 @@ class SwiftRecon(object):
|
|||||||
print("Device errors: %s on %s" % (entry, node))
|
print("Device errors: %s on %s" % (entry, node))
|
||||||
print("=" * 79)
|
print("=" * 79)
|
||||||
|
|
||||||
|
def server_type_check(self, hosts):
|
||||||
|
"""
|
||||||
|
Check for server types on the ring
|
||||||
|
|
||||||
|
:param hosts: set of hosts to check. in the format of:
|
||||||
|
set([('127.0.0.1', 6020), ('127.0.0.2', 6030)])
|
||||||
|
"""
|
||||||
|
errors = {}
|
||||||
|
recon = Scout("server_type_check", self.verbose, self.suppress_errors,
|
||||||
|
self.timeout)
|
||||||
|
print("[%s] Validating server type '%s' on %s hosts..." %
|
||||||
|
(self._ptime(), self.server_type, len(hosts)))
|
||||||
|
for url, response, status in self.pool.imap(
|
||||||
|
recon.scout_server_type, hosts):
|
||||||
|
if status == 200:
|
||||||
|
if response != self.server_type + '-server':
|
||||||
|
errors[url] = response
|
||||||
|
print("%s/%s hosts ok, %s error[s] while checking hosts." % (
|
||||||
|
len(hosts) - len(errors), len(hosts), len(errors)))
|
||||||
|
for host in errors:
|
||||||
|
print("Invalid: %s is %s" % (host, errors[host]))
|
||||||
|
print("=" * 79)
|
||||||
|
|
||||||
def expirer_check(self, hosts):
|
def expirer_check(self, hosts):
|
||||||
"""
|
"""
|
||||||
Obtain and print expirer statistics
|
Obtain and print expirer statistics
|
||||||
@ -872,6 +923,8 @@ class SwiftRecon(object):
|
|||||||
help="Get cluster load average stats")
|
help="Get cluster load average stats")
|
||||||
args.add_option('--quarantined', '-q', action="store_true",
|
args.add_option('--quarantined', '-q', action="store_true",
|
||||||
help="Get cluster quarantine stats")
|
help="Get cluster quarantine stats")
|
||||||
|
args.add_option('--validate-servers', action="store_true",
|
||||||
|
help="Validate servers on the ring")
|
||||||
args.add_option('--md5', action="store_true",
|
args.add_option('--md5', action="store_true",
|
||||||
help="Get md5sum of servers ring and compare to "
|
help="Get md5sum of servers ring and compare to "
|
||||||
"local copy")
|
"local copy")
|
||||||
@ -938,6 +991,7 @@ class SwiftRecon(object):
|
|||||||
self.get_ringmd5(hosts, swift_dir)
|
self.get_ringmd5(hosts, swift_dir)
|
||||||
self.quarantine_check(hosts)
|
self.quarantine_check(hosts)
|
||||||
self.socket_usage(hosts)
|
self.socket_usage(hosts)
|
||||||
|
self.server_type_check(hosts)
|
||||||
else:
|
else:
|
||||||
if options.async:
|
if options.async:
|
||||||
if self.server_type == 'object':
|
if self.server_type == 'object':
|
||||||
@ -966,6 +1020,8 @@ class SwiftRecon(object):
|
|||||||
self.expirer_check(hosts)
|
self.expirer_check(hosts)
|
||||||
else:
|
else:
|
||||||
print("Error: Can't check expired on non object servers.")
|
print("Error: Can't check expired on non object servers.")
|
||||||
|
if options.validate_servers:
|
||||||
|
self.server_type_check(hosts)
|
||||||
if options.loadstats:
|
if options.loadstats:
|
||||||
self.load_check(hosts)
|
self.load_check(hosts)
|
||||||
if options.diskusage:
|
if options.diskusage:
|
||||||
|
@ -56,6 +56,7 @@ class TestScout(unittest.TestCase):
|
|||||||
def setUp(self, *_args, **_kwargs):
|
def setUp(self, *_args, **_kwargs):
|
||||||
self.scout_instance = recon.Scout("type", suppress_errors=True)
|
self.scout_instance = recon.Scout("type", suppress_errors=True)
|
||||||
self.url = 'http://127.0.0.1:8080/recon/type'
|
self.url = 'http://127.0.0.1:8080/recon/type'
|
||||||
|
self.server_type_url = 'http://127.0.0.1:8080/'
|
||||||
|
|
||||||
@mock.patch('eventlet.green.urllib2.urlopen')
|
@mock.patch('eventlet.green.urllib2.urlopen')
|
||||||
def test_scout_ok(self, mock_urlopen):
|
def test_scout_ok(self, mock_urlopen):
|
||||||
@ -85,6 +86,37 @@ class TestScout(unittest.TestCase):
|
|||||||
self.assertTrue(isinstance(content, urllib2.HTTPError))
|
self.assertTrue(isinstance(content, urllib2.HTTPError))
|
||||||
self.assertEqual(status, 404)
|
self.assertEqual(status, 404)
|
||||||
|
|
||||||
|
@mock.patch('eventlet.green.urllib2.urlopen')
|
||||||
|
def test_scout_server_type_ok(self, mock_urlopen):
|
||||||
|
def getheader(name):
|
||||||
|
d = {'Server': 'server-type'}
|
||||||
|
return d.get(name)
|
||||||
|
mock_urlopen.return_value.info.return_value.getheader = getheader
|
||||||
|
url, content, status = self.scout_instance.scout_server_type(
|
||||||
|
("127.0.0.1", "8080"))
|
||||||
|
self.assertEqual(url, self.server_type_url)
|
||||||
|
self.assertEqual(content, 'server-type')
|
||||||
|
self.assertEqual(status, 200)
|
||||||
|
|
||||||
|
@mock.patch('eventlet.green.urllib2.urlopen')
|
||||||
|
def test_scout_server_type_url_error(self, mock_urlopen):
|
||||||
|
mock_urlopen.side_effect = urllib2.URLError("")
|
||||||
|
url, content, status = self.scout_instance.scout_server_type(
|
||||||
|
("127.0.0.1", "8080"))
|
||||||
|
self.assertTrue(isinstance(content, urllib2.URLError))
|
||||||
|
self.assertEqual(url, self.server_type_url)
|
||||||
|
self.assertEqual(status, -1)
|
||||||
|
|
||||||
|
@mock.patch('eventlet.green.urllib2.urlopen')
|
||||||
|
def test_scout_server_type_http_error(self, mock_urlopen):
|
||||||
|
mock_urlopen.side_effect = urllib2.HTTPError(
|
||||||
|
self.server_type_url, 404, "Internal error", None, None)
|
||||||
|
url, content, status = self.scout_instance.scout_server_type(
|
||||||
|
("127.0.0.1", "8080"))
|
||||||
|
self.assertEqual(url, self.server_type_url)
|
||||||
|
self.assertTrue(isinstance(content, urllib2.HTTPError))
|
||||||
|
self.assertEqual(status, 404)
|
||||||
|
|
||||||
|
|
||||||
class TestRecon(unittest.TestCase):
|
class TestRecon(unittest.TestCase):
|
||||||
def setUp(self, *_args, **_kwargs):
|
def setUp(self, *_args, **_kwargs):
|
||||||
@ -289,6 +321,86 @@ class TestReconCommands(unittest.TestCase):
|
|||||||
|
|
||||||
return mock.patch('eventlet.green.urllib2.urlopen', fake_urlopen)
|
return mock.patch('eventlet.green.urllib2.urlopen', fake_urlopen)
|
||||||
|
|
||||||
|
def test_server_type_check(self):
|
||||||
|
hosts = [('127.0.0.1', 6010), ('127.0.0.1', 6011),
|
||||||
|
('127.0.0.1', 6012)]
|
||||||
|
|
||||||
|
# sample json response from http://<host>:<port>/
|
||||||
|
responses = {6010: 'object-server', 6011: 'container-server',
|
||||||
|
6012: 'account-server'}
|
||||||
|
|
||||||
|
def mock_scout_server_type(app, host):
|
||||||
|
url = 'http://%s:%s/' % (host[0], host[1])
|
||||||
|
response = responses[host[1]]
|
||||||
|
status = 200
|
||||||
|
return url, response, status
|
||||||
|
|
||||||
|
stdout = StringIO()
|
||||||
|
patches = [
|
||||||
|
mock.patch('swift.cli.recon.Scout.scout_server_type',
|
||||||
|
mock_scout_server_type),
|
||||||
|
mock.patch('sys.stdout', new=stdout),
|
||||||
|
]
|
||||||
|
|
||||||
|
res_object = 'Invalid: http://127.0.0.1:6010/ is object-server'
|
||||||
|
res_container = 'Invalid: http://127.0.0.1:6011/ is container-server'
|
||||||
|
res_account = 'Invalid: http://127.0.0.1:6012/ is account-server'
|
||||||
|
valid = "1/1 hosts ok, 0 error[s] while checking hosts."
|
||||||
|
|
||||||
|
#Test for object server type - default
|
||||||
|
with nested(*patches):
|
||||||
|
self.recon.server_type_check(hosts)
|
||||||
|
|
||||||
|
output = stdout.getvalue()
|
||||||
|
self.assertTrue(res_container in output.splitlines())
|
||||||
|
self.assertTrue(res_account in output.splitlines())
|
||||||
|
stdout.truncate(0)
|
||||||
|
|
||||||
|
#Test ok for object server type - default
|
||||||
|
with nested(*patches):
|
||||||
|
self.recon.server_type_check([hosts[0]])
|
||||||
|
|
||||||
|
output = stdout.getvalue()
|
||||||
|
self.assertTrue(valid in output.splitlines())
|
||||||
|
stdout.truncate(0)
|
||||||
|
|
||||||
|
#Test for account server type
|
||||||
|
with nested(*patches):
|
||||||
|
self.recon.server_type = 'account'
|
||||||
|
self.recon.server_type_check(hosts)
|
||||||
|
|
||||||
|
output = stdout.getvalue()
|
||||||
|
self.assertTrue(res_container in output.splitlines())
|
||||||
|
self.assertTrue(res_object in output.splitlines())
|
||||||
|
stdout.truncate(0)
|
||||||
|
|
||||||
|
#Test ok for account server type
|
||||||
|
with nested(*patches):
|
||||||
|
self.recon.server_type = 'account'
|
||||||
|
self.recon.server_type_check([hosts[2]])
|
||||||
|
|
||||||
|
output = stdout.getvalue()
|
||||||
|
self.assertTrue(valid in output.splitlines())
|
||||||
|
stdout.truncate(0)
|
||||||
|
|
||||||
|
#Test for container server type
|
||||||
|
with nested(*patches):
|
||||||
|
self.recon.server_type = 'container'
|
||||||
|
self.recon.server_type_check(hosts)
|
||||||
|
|
||||||
|
output = stdout.getvalue()
|
||||||
|
self.assertTrue(res_account in output.splitlines())
|
||||||
|
self.assertTrue(res_object in output.splitlines())
|
||||||
|
stdout.truncate(0)
|
||||||
|
|
||||||
|
#Test ok for container server type
|
||||||
|
with nested(*patches):
|
||||||
|
self.recon.server_type = 'container'
|
||||||
|
self.recon.server_type_check([hosts[1]])
|
||||||
|
|
||||||
|
output = stdout.getvalue()
|
||||||
|
self.assertTrue(valid in output.splitlines())
|
||||||
|
|
||||||
def test_get_swiftconfmd5(self):
|
def test_get_swiftconfmd5(self):
|
||||||
hosts = set([('10.1.1.1', 10000),
|
hosts = set([('10.1.1.1', 10000),
|
||||||
('10.2.2.2', 10000)])
|
('10.2.2.2', 10000)])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user