def _filter_rdir_host(allsrv): for srv in allsrv.get('srv', {}): if srv['type'] == 'rdir': return srv['host'] raise NotFound("No rdir service found in %s" % (allsrv,))
def assign_services(self, service_type, max_per_rdir=None, min_dist=None, service_id=None, reassign=False, **kwargs): """ Assign an rdir service to all `service_type` servers that aren't already assigned one. :param max_per_rdir: Maximum number of services an rdir can handle. :type max_per_rdir: `int` :param min_dist: Minimum required distance between any service and its assigned rdir service. :type min_dist: `int` :param service_id: Assign only this service ID. :type service_id: `str` :param reassign: Reassign an rdir service. :type reassign: `bool` :param dry_run: Display actions but do nothing. :type dry_run: `bool` :returns: The list of `service_type` services that were assigned rdir services. """ all_services = self.cs.all_services(service_type, **kwargs) if service_id: for provider in all_services: provider_id = provider['tags'].get('tag.service_id', provider['addr']) if service_id == provider_id: break else: raise ValueError('%s isn\'t a %s' % (service_id, service_type)) all_services = [provider] all_rdir = self.cs.all_services('rdir', True, **kwargs) if len(all_rdir) <= 0: raise ServiceUnavailable("No rdir service found in %s" % self.ns) by_id = _build_dict_by_id(self.ns, all_rdir) errors = list() for provider in all_services: provider_id = provider['tags'].get('tag.service_id', provider['addr']) try: resp = self.directory.list(RDIR_ACCT, provider_id, service_type='rdir', **kwargs) rdir_host = _filter_rdir_host(resp) try: rdir = by_id[_make_id(self.ns, 'rdir', rdir_host)] if reassign: rdir['tags']['stat.opened_db_count'] = \ rdir['tags'].get('stat.opened_db_count', 0) - 1 # TODO(adu) Delete database raise NotFound('Reassign an rdir services') provider['rdir'] = rdir except KeyError: self.logger.warn("rdir %s linked to %s %s seems down", rdir_host, service_type, provider_id) if reassign: raise NotFound('Reassign an rdir services') except NotFound: try: rdir = self._smart_link_rdir(provider_id, all_rdir, service_type=service_type, max_per_rdir=max_per_rdir, min_dist=min_dist, reassign=reassign, **kwargs) except OioException as exc: self.logger.warn("Failed to link an rdir to %s %s: %s", service_type, provider_id, exc) errors.append((provider_id, exc)) continue n_bases = by_id[rdir]['tags'].get("stat.opened_db_count", 0) by_id[rdir]['tags']["stat.opened_db_count"] = n_bases + 1 provider['rdir'] = by_id[rdir] except OioException as exc: self.logger.warn( "Failed to check rdir linked to %s %s " "(thus won't try to make the link): %s", service_type, provider_id, exc) errors.append((provider_id, exc)) if errors: # group_chunk_errors is flexible enough to accept service addresses errors = group_chunk_errors(errors) if len(errors) == 1: err, addrs = errors.popitem() oio_reraise(type(err), err, str(addrs)) else: raise OioException('Several errors encountered: %s' % errors) return all_services