Merge "in case you lose your builder backups"
This commit is contained in:
commit
438596fc0f
@ -25,11 +25,11 @@ from textwrap import wrap
|
|||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from swift.common import exceptions
|
from swift.common import exceptions
|
||||||
from swift.common.ring import RingBuilder
|
from swift.common.ring import RingBuilder, Ring
|
||||||
from swift.common.ring.builder import MAX_BALANCE
|
from swift.common.ring.builder import MAX_BALANCE
|
||||||
from swift.common.utils import lock_parent_directory
|
from swift.common.utils import lock_parent_directory
|
||||||
from swift.common.ring.utils import parse_search_value, parse_args, \
|
from swift.common.ring.utils import parse_search_value, parse_args, \
|
||||||
build_dev_from_opts
|
build_dev_from_opts, parse_builder_ring_filename_args
|
||||||
|
|
||||||
MAJOR_VERSION = 1
|
MAJOR_VERSION = 1
|
||||||
MINOR_VERSION = 3
|
MINOR_VERSION = 3
|
||||||
@ -697,6 +697,52 @@ swift-ring-builder <builder_file> write_ring
|
|||||||
ring_data.save(ring_file)
|
ring_data.save(ring_file)
|
||||||
exit(EXIT_SUCCESS)
|
exit(EXIT_SUCCESS)
|
||||||
|
|
||||||
|
def write_builder():
|
||||||
|
"""
|
||||||
|
swift-ring-builder <ring_file> write_builder [min_part_hours]
|
||||||
|
Recreate a builder from a ring file (lossy) if you lost your builder
|
||||||
|
backups. (Protip: don't lose your builder backups).
|
||||||
|
[min_part_hours] is one of those numbers lost to the builder,
|
||||||
|
you can change it with set_min_part_hours.
|
||||||
|
"""
|
||||||
|
if exists(builder_file):
|
||||||
|
print 'Cowardly refusing to overwrite existing ' \
|
||||||
|
'Ring Builder file: %s' % builder_file
|
||||||
|
exit(EXIT_ERROR)
|
||||||
|
if len(argv) > 3:
|
||||||
|
min_part_hours = int(argv[3])
|
||||||
|
else:
|
||||||
|
stderr.write("WARNING: default min_part_hours may not match "
|
||||||
|
"the value in the lost builder.\n")
|
||||||
|
min_part_hours = 24
|
||||||
|
ring = Ring(ring_file)
|
||||||
|
for dev in ring.devs:
|
||||||
|
dev.update({
|
||||||
|
'parts': 0,
|
||||||
|
'parts_wanted': 0,
|
||||||
|
})
|
||||||
|
builder_dict = {
|
||||||
|
'part_power': 32 - ring._part_shift,
|
||||||
|
'replicas': float(ring.replica_count),
|
||||||
|
'min_part_hours': min_part_hours,
|
||||||
|
'parts': ring.partition_count,
|
||||||
|
'devs': ring.devs,
|
||||||
|
'devs_changed': False,
|
||||||
|
'version': 0,
|
||||||
|
'_replica2part2dev': ring._replica2part2dev_id,
|
||||||
|
'_last_part_moves_epoch': None,
|
||||||
|
'_last_part_moves': None,
|
||||||
|
'_last_part_gather_start': 0,
|
||||||
|
'_remove_devs': [],
|
||||||
|
}
|
||||||
|
builder = RingBuilder(1, 1, 1)
|
||||||
|
builder.copy_from(builder_dict)
|
||||||
|
for parts in builder._replica2part2dev:
|
||||||
|
for dev_id in parts:
|
||||||
|
builder.devs[dev_id]['parts'] += 1
|
||||||
|
builder._set_parts_wanted()
|
||||||
|
builder.save(builder_file)
|
||||||
|
|
||||||
def pretend_min_part_hours_passed():
|
def pretend_min_part_hours_passed():
|
||||||
builder.pretend_min_part_hours_passed()
|
builder.pretend_min_part_hours_passed()
|
||||||
builder.save(argv[1])
|
builder.save(argv[1])
|
||||||
@ -772,9 +818,11 @@ if __name__ == '__main__':
|
|||||||
' 2 = error')
|
' 2 = error')
|
||||||
exit(EXIT_SUCCESS)
|
exit(EXIT_SUCCESS)
|
||||||
|
|
||||||
if exists(argv[1]):
|
builder_file, ring_file = parse_builder_ring_filename_args(argv)
|
||||||
builder = RingBuilder.load(argv[1])
|
|
||||||
elif len(argv) < 3 or argv[2] != 'create':
|
if exists(builder_file):
|
||||||
|
builder = RingBuilder.load(builder_file)
|
||||||
|
elif len(argv) < 3 or argv[2] not in('create', 'write_builder'):
|
||||||
print 'Ring Builder file does not exist: %s' % argv[1]
|
print 'Ring Builder file does not exist: %s' % argv[1]
|
||||||
exit(EXIT_ERROR)
|
exit(EXIT_ERROR)
|
||||||
|
|
||||||
@ -785,11 +833,6 @@ if __name__ == '__main__':
|
|||||||
if err.errno != EEXIST:
|
if err.errno != EEXIST:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
ring_file = argv[1]
|
|
||||||
if ring_file.endswith('.builder'):
|
|
||||||
ring_file = ring_file[:-len('.builder')]
|
|
||||||
ring_file += '.ring.gz'
|
|
||||||
|
|
||||||
if len(argv) == 2:
|
if len(argv) == 2:
|
||||||
command = "default"
|
command = "default"
|
||||||
else:
|
else:
|
||||||
|
@ -269,6 +269,22 @@ def parse_args(argvish):
|
|||||||
return parser.parse_args(argvish)
|
return parser.parse_args(argvish)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_builder_ring_filename_args(argvish):
|
||||||
|
first_arg = argvish[1]
|
||||||
|
if first_arg.endswith('.ring.gz'):
|
||||||
|
ring_file = first_arg
|
||||||
|
builder_file = first_arg[:-len('.ring.gz')] + '.builder'
|
||||||
|
else:
|
||||||
|
builder_file = first_arg
|
||||||
|
if not builder_file.endswith('.builder'):
|
||||||
|
ring_file = first_arg
|
||||||
|
else:
|
||||||
|
ring_file = builder_file[:-len('.builder')]
|
||||||
|
if not first_arg.endswith('.ring.gz'):
|
||||||
|
ring_file += '.ring.gz'
|
||||||
|
return builder_file, ring_file
|
||||||
|
|
||||||
|
|
||||||
def build_dev_from_opts(opts):
|
def build_dev_from_opts(opts):
|
||||||
"""
|
"""
|
||||||
Convert optparse stype options into a device dictionary.
|
Convert optparse stype options into a device dictionary.
|
||||||
|
@ -17,7 +17,8 @@ import unittest
|
|||||||
|
|
||||||
from swift.common.ring.utils import (build_tier_tree, tiers_for_dev,
|
from swift.common.ring.utils import (build_tier_tree, tiers_for_dev,
|
||||||
parse_search_value, parse_args,
|
parse_search_value, parse_args,
|
||||||
build_dev_from_opts)
|
build_dev_from_opts,
|
||||||
|
parse_builder_ring_filename_args)
|
||||||
|
|
||||||
|
|
||||||
class TestUtils(unittest.TestCase):
|
class TestUtils(unittest.TestCase):
|
||||||
@ -139,6 +140,25 @@ class TestUtils(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
self.assertEquals(device, expected)
|
self.assertEquals(device, expected)
|
||||||
|
|
||||||
|
def test_parse_builder_ring_filename_args(self):
|
||||||
|
args = 'swift-ring-builder object.builder write_ring'
|
||||||
|
self.assertEquals((
|
||||||
|
'object.builder', 'object.ring.gz'
|
||||||
|
), parse_builder_ring_filename_args(args.split()))
|
||||||
|
args = 'swift-ring-builder container.ring.gz write_builder'
|
||||||
|
self.assertEquals((
|
||||||
|
'container.builder', 'container.ring.gz'
|
||||||
|
), parse_builder_ring_filename_args(args.split()))
|
||||||
|
# builer name arg should always fall through
|
||||||
|
args = 'swift-ring-builder test create'
|
||||||
|
self.assertEquals((
|
||||||
|
'test', 'test.ring.gz'
|
||||||
|
), parse_builder_ring_filename_args(args.split()))
|
||||||
|
args = 'swift-ring-builder my.file.name create'
|
||||||
|
self.assertEquals((
|
||||||
|
'my.file.name', 'my.file.name.ring.gz'
|
||||||
|
), parse_builder_ring_filename_args(args.split()))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
Reference in New Issue
Block a user