diff --git a/swift/cli/ringbuilder.py b/swift/cli/ringbuilder.py index 1e1f2d97a4..087d677540 100644 --- a/swift/cli/ringbuilder.py +++ b/swift/cli/ringbuilder.py @@ -517,7 +517,10 @@ swift-ring-builder balance_per_dev = builder._build_balance_per_dev() header_line, print_dev_f = _make_display_device_table(builder) print(header_line) - for dev in builder._iter_devs(): + for dev in sorted( + builder._iter_devs(), + key=lambda x: (x['region'], x['zone'], x['ip'], x['device']) + ): flags = 'DEL' if dev in builder._remove_devs else '' print_dev_f(dev, balance_per_dev[dev['id']], flags) exit(EXIT_SUCCESS) diff --git a/test/unit/cli/test_default_sorted_output.stub b/test/unit/cli/test_default_sorted_output.stub new file mode 100644 index 0000000000..ab510fd3d3 --- /dev/null +++ b/test/unit/cli/test_default_sorted_output.stub @@ -0,0 +1,10 @@ +__RINGFILE__, build version 9, id __BUILDER_ID__ +64 partitions, 3.000000 replicas, 2 regions, 4 zones, 4 devices, 100.00 balance, 0.00 dispersion +The minimum number of hours before a partition can be reassigned is 1 (1:00:00 remaining) +The overload factor is 0.00% (0.000000) +Ring file __RINGFILE__.ring.gz is obsolete +Devices: id region zone ip address:port replication ip:port name weight partitions balance flags meta + 1 1 1 127.0.0.2:6201 127.0.0.2:6201 sda2 100.00 64 33.33 + 4 1 2 127.0.0.5:6004 127.0.0.5:6004 sda5 100.00 64 33.33 + 0 2 1 127.0.0.6:6005 127.0.0.6:6005 sdb6 100.00 0 -100.00 + 2 2 2 127.0.0.3:6202 127.0.0.3:6202 sdc3 100.00 64 33.33 diff --git a/test/unit/cli/test_ringbuilder.py b/test/unit/cli/test_ringbuilder.py index 568286c019..96eded2fac 100644 --- a/test/unit/cli/test_ringbuilder.py +++ b/test/unit/cli/test_ringbuilder.py @@ -1754,6 +1754,41 @@ class TestCommands(unittest.TestCase, RunSwiftRingBuilderMixin): (self.tmpfile, ring.id, self.tmpfile) self.assertEqual(expected, mock_stdout.getvalue()) + def test_default_sorted_output(self): + mock_stdout = six.StringIO() + mock_stderr = six.StringIO() + + # Create a sample ring and remove/add some devices. + ring = self.create_sample_ring() + argv = ["", self.tmpfile, "add", + "--region", "1", "--zone", "2", + "--ip", "127.0.0.5", "--port", "6004", + "--replication-ip", "127.0.0.5", + "--replication-port", "6004", + "--device", "sda5", "--weight", "100.0"] + self.assertRaises(SystemExit, ringbuilder.main, argv) + argv = ["", self.tmpfile, "remove", "--id", "0"] + self.assertRaises(SystemExit, ringbuilder.main, argv) + argv = ["", self.tmpfile, "remove", "--id", "3"] + self.assertRaises(SystemExit, ringbuilder.main, argv) + argv = ["", self.tmpfile, "rebalance"] + self.assertRaises(SystemExit, ringbuilder.main, argv) + argv = \ + ["", self.tmpfile, "add", + "--region", "2", "--zone", "1", + "--ip", "127.0.0.6", "--port", "6005", + "--replication-ip", "127.0.0.6", + "--replication-port", "6005", + "--device", "sdb6", "--weight", "100.0"] + self.assertRaises(SystemExit, ringbuilder.main, argv) + + # Check the order of the devices listed the output. + argv = ["", self.tmpfile] + with mock.patch("sys.stdout", mock_stdout): + with mock.patch("sys.stderr", mock_stderr): + self.assertRaises(SystemExit, ringbuilder.main, argv) + self.assertOutputStub(mock_stdout.getvalue(), builder_id=ring.id) + def test_default_ringfile_check(self): self.create_sample_ring()