def write_stub_builder(tmpdir, region=1, name=''): """ Pretty much just a three node, three replica, 8 part power builder... :param tmpdir: a place to write the builder, be sure to clean it up! :param region: an integer, fills in region and ip :param name: the name of the builder (i.e. <name>.builder) """ name = name or str(region) replicas = 3 builder = RingBuilder(8, replicas, 1) for i in range(replicas): dev = { 'weight': 100, 'region': '%d' % region, 'zone': '1', 'ip': '10.0.0.%d' % region, 'port': '3600', 'device': 'sdb%d' % i } builder.add_dev(dev) builder.rebalance() builder_file = os.path.join(tmpdir, '%s.builder' % name) builder.save(builder_file) return builder, builder_file
def gen_builder(self, balanced=False): builder = RingBuilder(18, 3, 1) for i in xrange(self.device_count): zone = i ipaddr = "1.1.1.1" port = 6010 device_name = "sd%s" % i weight = 100.0 meta = "meta for %s" % i next_dev_id = 0 if builder.devs: next_dev_id = max(d['id'] for d in builder.devs if d) + 1 builder.add_dev({ 'id': next_dev_id, 'zone': zone, 'ip': ipaddr, 'port': int(port), 'device': device_name, 'weight': weight, 'meta': meta }) # add an empty dev builder.devs.append(None) if balanced: builder.rebalance() return builder
def test_different_part_power_error(self): # create a ring builder # (default, part power is 6 with create_sample_ringbuilders) builders = self.create_sample_ringbuilders(1) # prepare another ring which has different part power incorrect_builder = RingBuilder(4, 3, 1) _, fname = tempfile.mkstemp(dir=self.tmpdir) for _ in range(4): dev = self.pop_region_device(1) incorrect_builder.add_dev(dev) incorrect_builder.rebalance() incorrect_builder.save(fname) # sanity self.assertTrue(os.path.exists(fname)) # sanity correct_builder = builders[0] self.assertNotEqual(correct_builder.part_shift, incorrect_builder.part_shift) self.assertNotEqual(correct_builder.part_power, incorrect_builder.part_power) builders.append(incorrect_builder) with self.assertRaises(ValueError) as cm: compose_rings(builders) self.assertIn("All builders must have same value for 'part_power'", cm.exception.message)
def create_sample_ringbuilders(self, num_builders=2): """ Create sample rings with four devices :returns: a list of ring builder instances """ builders = [] for region in range(num_builders): fname = os.path.join(self.tmpdir, 'builder_%s.builder' % region) builder = RingBuilder(6, 3, 0) for _ in range(5): dev = self.pop_region_device(region) builder.add_dev(dev) # remove last dev to simulate a ring with some history builder.remove_dev(dev['id']) # add a dev that won't be assigned any parts new_dev = self.pop_region_device(region) new_dev['weight'] = 0 builder.add_dev(new_dev) builder.rebalance() builder.save(fname) self.assertTrue(os.path.exists(fname)) builders.append(builder) return builders
def test_composite_same_device_in_the_different_rings_error(self): builders = self.create_sample_ringbuilders(2) same_device = copy.deepcopy(builders[0].devs[0]) # create one more ring which duplicates a device in the first ring builder = RingBuilder(6, 3, 1) _, fname = tempfile.mkstemp(dir=self.tmpdir) # add info to feed to add_dev same_device.update({'region': 2, 'weight': 100}) builder.add_dev(same_device) # add rest of the devices, which are unique for _ in range(3): dev = self.pop_region_device(2) builder.add_dev(dev) builder.rebalance() builder.save(fname) # sanity self.assertTrue(os.path.exists(fname)) builders.append(builder) with self.assertRaises(ValueError) as cm: compose_rings(builders) self.assertIn( 'Duplicate ip/port/device combination %(ip)s/%(port)s/%(device)s ' 'found in builders at indexes 0 and 2' % same_device, cm.exception.message)
def test_compose_rings_float_replica_count_builder_error(self): builders = self.create_sample_ringbuilders(1) # prepare another ring which has float replica count incorrect_builder = RingBuilder(6, 1.5, 1) _, fname = tempfile.mkstemp(dir=self.tmpdir) for _ in range(4): dev = self.pop_region_device(1) incorrect_builder.add_dev(dev) incorrect_builder.rebalance() incorrect_builder.save(fname) # sanity self.assertTrue(os.path.exists(fname)) self.assertEqual(1.5, incorrect_builder.replicas) # the first replica has 2 ** 6 partitions self.assertEqual( 2 ** 6, len(incorrect_builder._replica2part2dev[0])) # but the second replica has the half of the first partitions self.assertEqual( 2 ** 5, len(incorrect_builder._replica2part2dev[1])) builders.append(incorrect_builder) with self.assertRaises(ValueError) as cm: compose_rings(builders) self.assertIn("Problem with builders", cm.exception.message) self.assertIn("Non integer replica count", cm.exception.message)
def write_ring(args, devices, builderfile): # Make an educated guess about the used port. These are the defaults for # TripleO-based deployments in Mitaka builder_fname = os.path.basename(builderfile) if 'account' in builder_fname: port = 6002 elif 'container' in builder_fname: port = 6001 elif 'object' in builder_fname: port = 6000 else: port = 6000 logging.debug('Set port for new devices to %d' % port) if not os.path.isfile(builderfile): logging.info( '%s not found, creating new builder file', builderfile) rb = RingBuilder(args.part_power, args.replicas, args.min_part_hours) else: logging.info('Using existing builder file %s', builderfile) rb = RingBuilder.load(builderfile) # Add all missing devices for dev in devices: _dev = rb.search_devs({'meta': dev['meta']}) if not _dev: dev['weight'] = float(dev.get('size')) / 10**9 dev['region'] = 1 dev['zone'] = 1 dev['port'] = port dev['replication_ip'] = dev['ip'] dev['replication_port'] = dev['port'] rb.add_dev(dev) logging.info('Added device %s / %s', dev['ip'], dev['device']) else: logging.info( 'Ignoring existing device %s / %s', dev['ip'], dev['device']) try: rb.rebalance() except RingValidationError as exc: logging.error(exc) rb.save(builderfile) ring_file = os.path.splitext(builderfile)[0] + '.ring.gz' ring_data = rb.get_ring() ring_data.save(ring_file) return [builderfile, ring_file]
def _write_stub_builder(self, region): replicas = 3 builder = RingBuilder(8, replicas, 1) for i in range(replicas): dev = { 'weight': 100, 'region': '%d' % region, 'zone': '1', 'ip': '10.0.0.%d' % region, 'port': '3600', 'device': 'sdb%d' % i } builder.add_dev(dev) builder.rebalance() builder_file = os.path.join(self.tmpdir, '%d.builder' % region) builder.save(builder_file) return builder, builder_file
def write_ring(args, devices, builderfile): # Make an educated guess about the used port. These are the defaults for # TripleO-based deployments in Mitaka builder_fname = os.path.basename(builderfile) if 'account' in builder_fname: port = 6002 elif 'container' in builder_fname: port = 6001 elif 'object' in builder_fname: port = 6000 else: port = 6000 logging.debug('Set port for new devices to %d' % port) if not os.path.isfile(builderfile): logging.info('%s not found, creating new builder file', builderfile) rb = RingBuilder(args.part_power, args.replicas, args.min_part_hours) else: logging.info('Using existing builder file %s', builderfile) rb = RingBuilder.load(builderfile) # Add all missing devices for dev in devices: _dev = rb.search_devs({'meta': dev['meta']}) if not _dev: dev['weight'] = float(dev.get('size')) / 10**9 dev['region'] = 1 dev['zone'] = 1 dev['port'] = port dev['replication_ip'] = dev['ip'] dev['replication_port'] = dev['port'] rb.add_dev(dev) logging.info('Added device %s / %s', dev['ip'], dev['device']) else: logging.info('Ignoring existing device %s / %s', dev['ip'], dev['device']) try: rb.rebalance() except RingValidationError as exc: logging.error(exc) rb.save(builderfile) ring_file = os.path.splitext(builderfile)[0] + '.ring.gz' ring_data = rb.get_ring() ring_data.save(ring_file) return [builderfile, ring_file]
def remake_rings(partpower=16, weight=100, replicas=3, min_part_hours=1, drives=False): for service in ['object', 'container', 'account']: builder_file = '/etc/swift/%s.builder' % service ring_file = '/etc/swift/%s.ring.gz' % service try: os.remove(builder_file) os.remove(ring_file) except OSError: pass builder = RingBuilder(partpower, replicas, min_part_hours) builder.save(builder_file) devstrs = _get_builder_strings(service, drives) for devstr in devstrs: new_dev = _parse_add_values(devstr, str(weight)) builder.add_dev(new_dev[0]) builder.save(builder_file) builder.rebalance(builder_file) builder.get_ring().save(ring_file)
def gen_builder(self, balanced=False): builder = RingBuilder(18, 3, 1) for i in xrange(self.device_count): zone = i ipaddr = "1.1.1.1" port = 6010 device_name = "sd%s" % i weight = 100.0 meta = "meta for %s" % i next_dev_id = 0 if builder.devs: next_dev_id = max(d['id'] for d in builder.devs if d) + 1 builder.add_dev({'id': next_dev_id, 'zone': zone, 'ip': ipaddr, 'port': int(port), 'device': device_name, 'weight': weight, 'meta': meta}) if balanced: builder.rebalance() return builder
def write_stub_builder(tmpdir, region=1, name=''): """ Pretty much just a three node, three replica, 8 part power builder... :param tmpdir: a place to write the builder, be sure to clean it up! :param region: an integer, fills in region and ip :param name: the name of the builder (i.e. <name>.builder) """ name = name or str(region) replicas = 3 builder = RingBuilder(8, replicas, 1) for i in range(replicas): dev = {'weight': 100, 'region': '%d' % region, 'zone': '1', 'ip': '10.0.0.%d' % region, 'port': '3600', 'device': 'sdb%d' % i} builder.add_dev(dev) builder.rebalance() builder_file = os.path.join(tmpdir, '%s.builder' % name) builder.save(builder_file) return builder, builder_file
def test_different_replica_count_works(self): # create a ring builder # (default, part power is 6 with create_sample_ringbuilders) builders = self.create_sample_ringbuilders(1) # prepare another ring which has different replica count builder = RingBuilder(6, 1, 1) _, fname = tempfile.mkstemp(dir=self.tmpdir) for _ in range(4): dev = self.pop_region_device(1) builder.add_dev(dev) builder.rebalance() builder.save(fname) # sanity self.assertTrue(os.path.exists(fname)) builders.append(builder) rd = compose_rings(builders) rd.save(self.output_ring) got_ring = Ring(self.output_ring) self.assertEqual(got_ring.partition_count, 2**6) self.assertEqual(got_ring.replica_count, 4) # 3 + 1 self.assertEqual(got_ring._part_shift, 26) self.assertDevices(got_ring, builders)