Beispiel #1
0
 def add_to_ring(self, builder_type, body, lasthash, start_response, env):
     """ Handle a add device post """
     with lock_file(self.bf_path[builder_type], timeout=1, unlink=False):
         self.verify_current_hash(self.bf_path[builder_type], lasthash)
         builder = RingBuilder.load(self.bf_path[builder_type])
         ring_modified = False
         try:
             for device in body['devices']:
                 sleep()  # so we don't starve/block
                 if not self._is_existing_dev(builder, device['ip'],
                                              int(device['port']),
                                              device['device']):
                     self._add_device(builder, int(device['zone']),
                                      device['ip'], int(device['port']),
                                      device['device'],
                                      float(device['weight']),
                                      device['meta'])
                     ring_modified = True
         except (AttributeError, KeyError, ValueError, TypeError) as err:
             return self.return_response(False, lasthash,
                                         "Malformed request.",
                                         start_response, env)
         if ring_modified:
             newmd5 = self.write_builder(builder,
                                         self.bf_path[builder_type])
             return self.return_response(True, newmd5, None,
                                         start_response, env)
         else:
             return self.return_response(False, lasthash,
                                         'Ring remains unchanged.',
                                         start_response, env)
Beispiel #2
0
    def change_weight(self, builder_type, dev_weights, lasthash,
                      start_response, env):
        """ Change weight of devices

        :param builder_type: the builder_type to use when loading the builder
        :param dev_weights: a dict of device id and weight
        :param lasthash: the hash to use when verifying state
        """
        with lock_file(self.bf_path[builder_type], timeout=1, unlink=False):
            self.verify_current_hash(self.bf_path[builder_type], lasthash)
            builder = RingBuilder.load(self.bf_path[builder_type])
            for dev_id in dev_weights:
                sleep()  # so we don't starve/block
                try:
                    builder.set_dev_weight(int(dev_id),
                                           float(dev_weights[dev_id]))
                except (IndexError, TypeError):
                    return self.return_response(False, lasthash,
                                                'Invalid dev id %s.' % dev_id,
                                                start_response, env)
                except ValueError as err:
                    return self.return_response(False, lasthash, str(err),
                                                start_response, env)
            newmd5 = self.write_builder(builder, self.bf_path[builder_type])
            return self.return_response(True, newmd5, None, start_response,
                                        env)
Beispiel #3
0
    def change_meta(self, builder_type, dev_meta, lasthash, start_response,
                    env):
        """ Change meta info for devices

        :param builder_type: the builder_type to use when loading the builder
        :param dev_meta: a dict of device id and meta info
        :param lasthash: the hash to use when verifying state
        """
        with lock_file(self.bf_path[builder_type], timeout=1, unlink=False):
            self.verify_current_hash(self.bf_path[builder_type], lasthash)
            builder = RingBuilder.load(self.bf_path[builder_type])
            try:
                modified = False
                for dev_id in dev_meta:
                    sleep()  # so we don't starve/block
                    for device in builder.devs:
                        if not device:
                            continue
                        if device['id'] == int(dev_id):
                            modified = True
                            device['meta'] = '%s' % dev_meta[dev_id]
                if modified:
                    newmd5 = self.write_builder(builder,
                                                self.bf_path[builder_type])
                    return self.return_response(True, newmd5, None,
                                                start_response, env)
                else:
                    return self.return_response(False, lasthash,
                                                'Invalid dev id %s.' % dev_id,
                                                start_response, env)
            except ValueError as err:
                return self.return_response(False, lasthash, str(err),
                                            start_response, env)
Beispiel #4
0
    def remove_devs(self, builder_type, devices, lasthash, start_response,
                    env):
        """ remove devices from the builder

        :params builder_type: the builder_type to use when loading the builder
        :params devices: list of device ids to be removed.
        :params lasthash: the hash to use when verifying state
        """
        with lock_file(self.bf_path[builder_type], timeout=1, unlink=False):
            self.verify_current_hash(self.bf_path[builder_type], lasthash)
            builder = RingBuilder.load(self.bf_path[builder_type])
            if not isinstance(devices, list):
                return self.return_response(False, lasthash,
                                            'Malformed request.',
                                            start_response, env)
            for dev_id in devices:
                sleep()  # so we don't starve/block
                try:
                    builder.remove_dev(int(dev_id))
                except (IndexError, TypeError):
                    return self.return_response(False, lasthash,
                                                'Invalid dev id %s.' % dev_id,
                                                start_response, env)
                except RingBuilderError as err:
                    return self.return_response(False, lasthash,
                                                'Error removing %s - %s.' %
                                                (dev_id, err),
                                                start_response, env)
                except ValueError as err:
                    return self.return_response(False, lasthash, str(err),
                                                start_response, env)
            newmd5 = self.write_builder(builder, self.bf_path[builder_type])
            return self.return_response(True, newmd5, None, start_response,
                                        env)
Beispiel #5
0
    def rebalance(self, builder_type, lasthash, start_response, env):
        """ rebalance a ring

            note: rebalance doesn't yield.
        """
        with lock_file(self.bf_path[builder_type], timeout=1, unlink=False):
            self.verify_current_hash(self.bf_path[builder_type], lasthash)
            builder = RingBuilder.load(self.bf_path[builder_type])
            devs_changed = builder.devs_changed
            try:
                last_balance = builder.get_balance()
                parts, balance = builder.rebalance()
            except RingBuilderError, err:
                self.logger.exception(_("Error during ring validation."))
                return self.return_response(False, None, err.message,
                                            start_response, env)
            if not parts:
                msg = 'Either none need to be assigned or none can be due ' \
                      'to min_part_hours [%s].' % builder.min_part_hours
                self.logger.error(_(msg))
                return self.return_response(False, None, msg, start_response,
                                            env)
            if not devs_changed and abs(last_balance - balance) < 1:
                msg = 'Refusing to save rebalance. Did not change at least 1%.'
                self.logger.error(_(msg))
                return self.return_response(False, None, msg, start_response,
                                            env)
            try:
                builder.validate()
            except RingValidationError, err:
                self.logger.exception(_("Error during ring validation."))
                return self.return_response(False, None, err.message,
                                            start_response, env)
Beispiel #6
0
    def handle_head(self, target_file, start_response, env):
        """handle a head request. at this point it simply obtains the targets
        md5sum.

        :params target_file: File whos md5sum to obtain.
        :returns: list of boolean status, md5sum of the current ring, and all
                  builder.devs
        """
        with lock_file(target_file, unlink=False):
            current_hash = self._get_md5sum(target_file)
            return self.return_response(True, current_hash, None,
                                        start_response, env)
Beispiel #7
0
    def list_devices(self, builder_type, start_response, env):
        """ list ALL devices in the ring

        :params builder_type: the builder_type to use when loading the builder
        :returns: list of boolean status, md5sum of the current ring, and all
                  builder.devs
        """
        with lock_file(self.bf_path[builder_type], timeout=1, unlink=False):
            builder = RingBuilder.load(self.bf_path[builder_type])
            current_md5sum = self._get_md5sum(self.bf_path[builder_type])
            return self.return_response(True, current_md5sum, builder.devs,
                                        start_response, env)
Beispiel #8
0
    def return_static_file(self, filename, start_response, env):
        """ lock and serve a static file to the client from disk

        :params filename: the file to serve and who's md5sum to use
                          for the X-Current-Hash header.
        :params start_response: start_response object
        :returns: iterator for reading the file from disk.
        """
        with lock_file(filename, timeout=1, unlink=False):
            filehash = self._get_md5sum(filename)
            self._log_request(env, 200)
            start_response('200 OK', [('Content-Length', getsize(filename)),
                                      ('X-Current-Hash', filehash),
                                      ('Content-Type',
                                       'application/octet-stream')])
            return FileIterable(filename)
 def flush(self):
     while self.buffers:
         filename_list = self.buffers.keys()
         for filename in filename_list:
             out = '\n'.join(self.buffers[filename]) + '\n'
             mid_dirs = os.path.dirname(filename)
             try:
                 os.makedirs(mid_dirs)
             except OSError, err:
                 if err.errno == errno.EEXIST:
                     pass
                 else:
                     raise
             try:
                 with lock_file(filename, append=True, unlink=False) as f:
                     f.write(out)
             except LockTimeout:
                 # couldn't write, we'll try again later
                 self.logger.debug(_('Timeout writing to %s' % filename))
             else:
                 del self.buffers[filename]
Beispiel #10
0
 def flush(self):
     while self.buffers:
         filename_list = self.buffers.keys()
         for filename in filename_list:
             out = '\n'.join(self.buffers[filename]) + '\n'
             mid_dirs = os.path.dirname(filename)
             try:
                 os.makedirs(mid_dirs)
             except OSError, err:
                 if err.errno == errno.EEXIST:
                     pass
                 else:
                     raise
             try:
                 with lock_file(filename, append=True, unlink=False) as f:
                     f.write(out)
             except LockTimeout:
                 # couldn't write, we'll try again later
                 self.logger.debug(_('Timeout writing to %s' % filename))
             else:
                 del self.buffers[filename]
Beispiel #11
0
    def search(self, builder_type, search_pattern, start_response, env):
        """ search the builder for devices matching search pattern

        :params builder_type: the builder_type to use when loading the builder
        :params search_values: the value to search for
        :returns: list of boolean status, md5sum of current builder
                  file on disk, and error message or dict of matched devices.
        """
        with lock_file(self.bf_path[builder_type], timeout=1, unlink=False):
            builder = RingBuilder.load(self.bf_path[builder_type])
            try:
                search_result = builder.search_devs(str(search_pattern))
                return self.return_response(True, self._get_md5sum(
                                            self.bf_path[builder_type]),
                                            search_result,
                                            start_response, env)
            except ValueError:
                return self.return_response(False, self._get_md5sum(
                                            self.bf_path[builder_type]),
                                            'Invalid search term',
                                            start_response, env)