Add info about state of ring file to default command.

Try to find ring file, load and compare it with builder file, then show result state.
Examples:
Ring file object.ring.gz not found, probably it hasn't been written yet
Ring file object.ring.gz is up-to-date
Ring file object.ring.gz is obsolete
Ring file object.ring.gz is invalid: ValueError('string length not a multiple of item size',)

Change-Id: I4d769aa5fe1c2b1167ec088aa372874f7d13ae48
This commit is contained in:
Peter Lisák 2015-12-03 16:48:18 +01:00 committed by Ondřej Nový
parent 6a473e3d7b
commit f56f29ef7a
2 changed files with 81 additions and 2 deletions

View File

@ -33,7 +33,7 @@ from six.moves import zip as izip
from six.moves import input from six.moves import input
from swift.common import exceptions from swift.common import exceptions
from swift.common.ring import RingBuilder, Ring from swift.common.ring import RingBuilder, Ring, RingData
from swift.common.ring.builder import MAX_BALANCE from swift.common.ring.builder import MAX_BALANCE
from swift.common.ring.utils import validate_args, \ from swift.common.ring.utils import validate_args, \
validate_and_normalize_ip, build_dev_from_opts, \ validate_and_normalize_ip, build_dev_from_opts, \
@ -450,6 +450,23 @@ swift-ring-builder <builder_file>
timedelta(seconds=builder.min_part_seconds_left))) timedelta(seconds=builder.min_part_seconds_left)))
print('The overload factor is %0.2f%% (%.6f)' % ( print('The overload factor is %0.2f%% (%.6f)' % (
builder.overload * 100, builder.overload)) builder.overload * 100, builder.overload))
# compare ring file against builder file
if not exists(ring_file):
print('Ring file %s not found, '
'probably it hasn\'t been written yet' % ring_file)
else:
builder_dict = builder.get_ring().to_dict()
try:
ring_dict = RingData.load(ring_file).to_dict()
except Exception as exc:
print('Ring file %s is invalid: %r' % (ring_file, exc))
else:
if builder_dict == ring_dict:
print('Ring file %s is up-to-date' % ring_file)
else:
print('Ring file %s is obsolete' % ring_file)
if builder.devs: if builder.devs:
balance_per_dev = builder._build_balance_per_dev() balance_per_dev = builder._build_balance_per_dev()
print('Devices: id region zone ip address port ' print('Devices: id region zone ip address port '

View File

@ -16,6 +16,7 @@
import logging import logging
import mock import mock
import os import os
import re
import six import six
import tempfile import tempfile
import unittest import unittest
@ -1741,6 +1742,8 @@ class TestCommands(unittest.TestCase, RunSwiftRingBuilderMixin):
"The minimum number of hours before a partition can be " \ "The minimum number of hours before a partition can be " \
"reassigned is 1 (0:00:00 remaining)\n" \ "reassigned is 1 (0:00:00 remaining)\n" \
"The overload factor is 0.00%% (0.000000)\n" \ "The overload factor is 0.00%% (0.000000)\n" \
"Ring file %s.ring.gz not found, probably " \
"it hasn't been written yet\n" \
"Devices: id region zone ip address port " \ "Devices: id region zone ip address port " \
"replication ip replication port name weight " \ "replication ip replication port name weight " \
"partitions balance flags meta\n" \ "partitions balance flags meta\n" \
@ -1755,9 +1758,68 @@ class TestCommands(unittest.TestCase, RunSwiftRingBuilderMixin):
" 0 -100.00 \n" \ " 0 -100.00 \n" \
" 3 3 3 127.0.0.4 6003 " \ " 3 3 3 127.0.0.4 6003 " \
"127.0.0.4 6003 sdd4 0.00" \ "127.0.0.4 6003 sdd4 0.00" \
" 0 0.00 \n" % self.tmpfile " 0 0.00 \n" % (self.tmpfile, self.tmpfile)
self.assertEqual(expected, mock_stdout.getvalue()) self.assertEqual(expected, mock_stdout.getvalue())
def test_default_ringfile_check(self):
self.create_sample_ring()
# ring file not created
mock_stdout = six.StringIO()
mock_stderr = six.StringIO()
argv = ["", self.tmpfile]
with mock.patch("sys.stdout", mock_stdout):
with mock.patch("sys.stderr", mock_stderr):
self.assertRaises(SystemExit, ringbuilder.main, argv)
rnf = re.compile("Ring file .*\.ring\.gz not found")
self.assertTrue(rnf.findall(mock_stdout.getvalue()))
# write ring file
argv = ["", self.tmpfile, "rebalance"]
self.assertRaises(SystemExit, ringbuilder.main, argv)
# ring file is up-to-date
mock_stdout = six.StringIO()
argv = ["", self.tmpfile]
with mock.patch("sys.stdout", mock_stdout):
with mock.patch("sys.stderr", mock_stderr):
self.assertRaises(SystemExit, ringbuilder.main, argv)
rutd = re.compile("Ring file .*\.ring\.gz is up-to-date")
self.assertTrue(rutd.findall(mock_stdout.getvalue()))
# change builder (set weight)
argv = ["", self.tmpfile, "set_weight", "0", "--id", "3"]
self.assertRaises(SystemExit, ringbuilder.main, argv)
# ring file is obsolete after set_weight
mock_stdout = six.StringIO()
argv = ["", self.tmpfile]
with mock.patch("sys.stdout", mock_stdout):
with mock.patch("sys.stderr", mock_stderr):
self.assertRaises(SystemExit, ringbuilder.main, argv)
ro = re.compile("Ring file .*\.ring\.gz is obsolete")
self.assertTrue(ro.findall(mock_stdout.getvalue()))
# write ring file
argv = ["", self.tmpfile, "write_ring"]
self.assertRaises(SystemExit, ringbuilder.main, argv)
# ring file up-to-date again
mock_stdout = six.StringIO()
argv = ["", self.tmpfile]
with mock.patch("sys.stdout", mock_stdout):
with mock.patch("sys.stderr", mock_stderr):
self.assertRaises(SystemExit, ringbuilder.main, argv)
self.assertTrue(rutd.findall(mock_stdout.getvalue()))
# Break ring file e.g. just make it empty
open('%s.ring.gz' % self.tmpfile, 'w').close()
# ring file is invalid
mock_stdout = six.StringIO()
argv = ["", self.tmpfile]
with mock.patch("sys.stdout", mock_stdout):
with mock.patch("sys.stderr", mock_stderr):
self.assertRaises(SystemExit, ringbuilder.main, argv)
ro = re.compile("Ring file .*\.ring\.gz is invalid")
self.assertTrue(ro.findall(mock_stdout.getvalue()))
def test_rebalance(self): def test_rebalance(self):
self.create_sample_ring() self.create_sample_ring()
argv = ["", self.tmpfile, "rebalance", "3"] argv = ["", self.tmpfile, "rebalance", "3"]