예제 #1
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery=None,
                   limit=None):
        """Return an iterable of api_models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional ID of the resource.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        :param limit: Maximum number of results to return.
        """
        if limit == 0:
            return
        s_filter = storage.SampleFilter(user=user,
                                        project=project,
                                        source=source,
                                        metaquery=metaquery,
                                        resource=resource)

        # NOTE(gordc): get latest sample of each meter/resource. we do not
        #              filter here as we want to filter only on latest record.
        session = self._engine_facade.get_session()
        subq = session.query(func.max(models.Sample.id).label('id')).join(
            models.Resource,
            models.Resource.internal_id == models.Sample.resource_id).group_by(
                models.Sample.meter_id, models.Resource.resource_id)
        if resource:
            subq = subq.filter(models.Resource.resource_id == resource)
        subq = subq.subquery()

        # get meter details for samples.
        query_sample = (session.query(
            models.Sample.meter_id, models.Meter.name, models.Meter.type,
            models.Meter.unit, models.Resource.resource_id,
            models.Resource.project_id,
            models.Resource.source_id, models.Resource.user_id).join(
                subq, subq.c.id == models.Sample.id).join(
                    models.Meter,
                    models.Meter.id == models.Sample.meter_id).join(
                        models.Resource, models.Resource.internal_id ==
                        models.Sample.resource_id))
        query_sample = make_query_from_filter(session,
                                              query_sample,
                                              s_filter,
                                              require_meter=False)

        query_sample = query_sample.limit(limit) if limit else query_sample
        for row in query_sample.all():
            yield api_models.Meter(name=row.name,
                                   type=row.type,
                                   unit=row.unit,
                                   resource_id=row.resource_id,
                                   project_id=row.project_id,
                                   source=row.source_id,
                                   user_id=row.user_id)
예제 #2
0
    def get_meters(self, user=None, project=None, resource=None, source=None,
                   metaquery={}):
        """Return an iterable of models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional resource filter.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        """
        q = {}
        if user is not None:
            q['user_id'] = user
        if project is not None:
            q['project_id'] = project
        if resource is not None:
            q['_id'] = resource
        if source is not None:
            q['source'] = source
        q.update(metaquery)

        for r in self.db.resource.find(q):
            for r_meter in r['meter']:
                yield models.Meter(
                    name=r_meter['counter_name'],
                    type=r_meter['counter_type'],
                    # Return empty string if 'counter_unit' is not valid for
                    # backward compaitiblity.
                    unit=r_meter.get('counter_unit', ''),
                    resource_id=r['_id'],
                    project_id=r['project_id'],
                    user_id=r['user_id'],
                )
예제 #3
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery={}):
        """Return an iterable of models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional resource filter.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        """
        q = make_query(user=user,
                       project=project,
                       resource=resource,
                       source=source,
                       require_meter=False,
                       query_only=True)
        LOG.debug("Query Resource table: %s" % q)

        # handle metaquery
        if len(metaquery) > 0:
            meta_q = []
            for k, v in metaquery.iteritems():
                meta_q.append(
                    "SingleColumnValueFilter ('f', '%s', =, 'binary:%s')" %
                    ('r_' + k.split('.', 1)[1], v))
            meta_q = " AND ".join(meta_q)
            # join query and metaquery
            if q is not None:
                q += " AND " + meta_q
            else:
                q = meta_q  # metaquery only

        gen = self.resource.scan(filter=q)

        for ignored, data in gen:
            # Meter columns are stored like this:
            # "m_{counter_name}|{counter_type}|{counter_unit}" => "1"
            # where 'm' is a prefix (m for meter), value is always set to 1
            meter = None
            for m in data:
                if m.startswith('f:m_'):
                    meter = m
                    break
            if meter is None:
                continue
            name, type, unit = meter[4:].split("!")
            yield models.Meter(
                name=name,
                type=type,
                unit=unit,
                resource_id=data['f:resource_id'],
                project_id=data['f:project_id'],
                source=data['f:source'],
                user_id=data['f:user_id'],
            )
예제 #4
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery=None,
                   pagination=None):
        """Return an iterable of models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional resource filter.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        :param pagination: Optional pagination query.
        """

        metaquery = metaquery or {}

        if pagination:
            raise ceilometer.NotImplementedError(
                _('Pagination not implemented'))
        with self.conn_pool.connection() as conn:
            resource_table = conn.table(self.RESOURCE_TABLE)
            q = hbase_utils.make_query(metaquery=metaquery,
                                       user_id=user,
                                       project_id=project,
                                       resource_id=resource,
                                       source=source)
            LOG.debug(_("Query Resource table: %s") % q)

            gen = resource_table.scan(filter=q)
            # We need result set to be sure that user doesn't receive several
            # same meters. Please see bug
            # https://bugs.launchpad.net/ceilometer/+bug/1301371
            result = set()
            for ignored, data in gen:
                flatten_result, s, meters, md = hbase_utils.deserialize_entry(
                    data)
                for m in meters:
                    _m_rts, m_source, m_raw = m[0].split("+")
                    name, type, unit = m_raw.split('!')
                    meter_dict = {
                        'name': name,
                        'type': type,
                        'unit': unit,
                        'resource_id': flatten_result['resource_id'],
                        'project_id': flatten_result['project_id'],
                        'user_id': flatten_result['user_id']
                    }
                    frozen_meter = frozenset(meter_dict.items())
                    if frozen_meter in result:
                        continue
                    result.add(frozen_meter)
                    meter_dict.update(
                        {'source': m_source if m_source else None})

                    yield models.Meter(**meter_dict)
    def get_meters(user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery={}):
        """Return an iterable of api_models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional ID of the resource.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        """
        session = sqlalchemy_session.get_session()

        # Meter table will store large records and join with resource
        # will be very slow.
        # subquery_meter is used to reduce meter records
        # by selecting a record for each (resource_id, counter_name).
        # max() is used to choice a meter record, so the latest record
        # is selected for each (resource_id, counter_name).
        #
        subquery_meter = session.query(func.max(Meter.id).label('id')).\
            group_by(Meter.resource_id, Meter.counter_name).subquery()

        # The SQL of query_meter is essentially:
        #
        # SELECT meter.* FROM meter INNER JOIN
        #  (SELECT max(meter.id) AS id FROM meter
        #   GROUP BY meter.resource_id, meter.counter_name) AS anon_2
        # ON meter.id = anon_2.id
        #
        query_meter = session.query(Meter).\
            join(subquery_meter, Meter.id == subquery_meter.c.id)

        alias_meter = aliased(Meter, query_meter.subquery())
        query = session.query(Resource, alias_meter).join(
            alias_meter, Resource.id == alias_meter.resource_id)

        if user is not None:
            query = query.filter(Resource.user_id == user)
        if source is not None:
            query = query.filter(Resource.sources.any(id=source))
        if resource:
            query = query.filter(Resource.id == resource)
        if project is not None:
            query = query.filter(Resource.project_id == project)
        if metaquery:
            raise NotImplementedError('metaquery not implemented')

        for resource, meter in query.all():
            yield api_models.Meter(name=meter.counter_name,
                                   type=meter.counter_type,
                                   unit=meter.counter_unit,
                                   resource_id=resource.id,
                                   project_id=resource.project_id,
                                   source=resource.sources[0].id,
                                   user_id=resource.user_id)
예제 #6
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery=None,
                   pagination=None):
        """Return an iterable of api_models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional ID of the resource.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        :param pagination: Optional pagination query.
        """

        if pagination:
            raise NotImplementedError('Pagination not implemented')

        s_filter = storage.SampleFilter(user=user,
                                        project=project,
                                        source=source,
                                        metaquery=metaquery,
                                        resource=resource)

        session = self._engine_facade.get_session()

        # sample_subq is used to reduce sample records
        # by selecting a record for each (resource_id, meter_id).
        # max() is used to choice a sample record, so the latest record
        # is selected for each (resource_id, meter_id).
        sample_subq = (session.query(func.max(
            models.Sample.id).label('id')).group_by(models.Sample.meter_id,
                                                    models.Sample.resource_id))
        sample_subq = sample_subq.subquery()

        # SELECT sample.* FROM sample INNER JOIN
        #  (SELECT max(sample.id) AS id FROM sample
        #   GROUP BY sample.resource_id, sample.meter_id) AS anon_2
        # ON sample.id = anon_2.id
        query_sample = (session.query(models.MeterSample).join(
            sample_subq, models.MeterSample.id == sample_subq.c.id))
        query_sample = make_query_from_filter(session,
                                              query_sample,
                                              s_filter,
                                              require_meter=False)

        for sample in query_sample.all():
            yield api_models.Meter(name=sample.counter_name,
                                   type=sample.counter_type,
                                   unit=sample.counter_unit,
                                   resource_id=sample.resource_id,
                                   project_id=sample.project_id,
                                   source=sample.source_id,
                                   user_id=sample.user_id)
예제 #7
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery=None,
                   limit=None):
        """Return an iterable of models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional resource filter.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        :param limit: Maximum number of results to return.
        """
        if limit == 0:
            return

        metaquery = pymongo_utils.improve_keys(metaquery, metaquery=True) or {}

        q = {}
        if user == 'None':
            q['user_id'] = None
        elif user is not None:
            q['user_id'] = user
        if project == 'None':
            q['project_id'] = None
        elif project is not None:
            q['project_id'] = project
        if resource == 'None':
            q['_id'] = None
        elif resource is not None:
            q['_id'] = resource
        if source is not None:
            q['source'] = source
        q.update(metaquery)

        count = 0
        for r in self.db.resource.find(q):
            for r_meter in r['meter']:
                if limit and count >= limit:
                    return
                else:
                    count += 1
                yield models.Meter(
                    name=r_meter['counter_name'],
                    type=r_meter['counter_type'],
                    # Return empty string if 'counter_unit' is not valid for
                    # backward compatibility.
                    unit=r_meter.get('counter_unit', ''),
                    resource_id=r['_id'],
                    project_id=r['project_id'],
                    source=r['source'],
                    user_id=r['user_id'],
                )
예제 #8
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery={},
                   limit=None,
                   marker_pairs=None,
                   sort_key=None,
                   sort_dir=None):
        """Return an iterable of models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional resource filter.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        :param limit: Number of documents should be returned.
        :param marker_pairs: Attribute-value pairs to identify the last item of
                             the previous page.
        :param sort_key: Attribute by which results be sorted.
        :param sort_dir: Direction with which results be sorted(asc, desc).
        """
        q = {}
        if user is not None:
            q['user_id'] = user
        if project is not None:
            q['project_id'] = project
        if resource is not None:
            q['_id'] = resource
        if source is not None:
            q['source'] = source
        q.update(metaquery)

        marker = self._get_marker(self.db.resource, marker_pairs=marker_pairs)
        sort_keys = base._handle_sort_key('meter', sort_key)

        for r in self.paginate_query(q,
                                     self.db.resource,
                                     limit=limit,
                                     marker=marker,
                                     sort_keys=sort_keys,
                                     sort_dir=sort_dir):
            for r_meter in r['meter']:
                yield models.Meter(
                    name=r_meter['counter_name'],
                    type=r_meter['counter_type'],
                    # Return empty string if 'counter_unit' is not valid for
                    # backward compatibility.
                    unit=r_meter.get('counter_unit', ''),
                    resource_id=r['_id'],
                    project_id=r['project_id'],
                    source=r['source'],
                    user_id=r['user_id'],
                )
예제 #9
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   limit=None,
                   metaquery=None,
                   pagination=None):
        """Return an iterable of dictionaries containing meter information.

        { 'name': name of the meter,
          'type': type of the meter (gauge, delta, cumulative),
          'resource_id': UUID of the resource,
          'project_id': UUID of project owning the resource,
          'user_id': UUID of user owning the resource,
          }

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional resource filter.
        :param source: Optional source filter.
        :param limit: Maximum number of results to return.
        :param metaquery: Optional dict with metadata to match on.
        :param pagination: Optional pagination query.
        """
        if pagination:
            raise ceilometer.NotImplementedError('Pagination not implemented')

        if metaquery:
            raise ceilometer.NotImplementedError('Metaquery not implemented')

        _dimensions = dict(user_id=user,
                           project_id=project,
                           resource_id=resource,
                           source=source)

        _dimensions = {k: v for k, v in _dimensions.items() if v is not None}

        _search_kwargs = {'dimensions': _dimensions}

        if limit:
            _search_kwargs['limit'] = limit

        for metric in self.mc.metrics_list(**_search_kwargs):
            yield api_models.Meter(
                name=metric['name'],
                type=metric['dimensions'].get('type') or 'cumulative',
                unit=metric['dimensions'].get('unit'),
                resource_id=metric['dimensions'].get('resource_id'),
                project_id=metric['dimensions'].get('project_id'),
                source=metric['dimensions'].get('source'),
                user_id=metric['dimensions'].get('user_id'))
예제 #10
0
    def get_meters(self, user=None, project=None, resource=None, source=None,
                   metaquery=None, limit=None):
        """Return an iterable of models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional resource filter.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        :param limit: Maximum number of results to return.
        """
        if limit == 0:
            return

        metaquery = metaquery or {}

        with self.conn_pool.connection() as conn:
            resource_table = conn.table(self.RESOURCE_TABLE)
            q = hbase_utils.make_query(metaquery=metaquery, user_id=user,
                                       project_id=project,
                                       resource_id=resource,
                                       source=source)
            LOG.debug("Query Resource table: %s", q)

            gen = resource_table.scan(filter=q)
            # We need result set to be sure that user doesn't receive several
            # same meters. Please see bug
            # https://bugs.launchpad.net/ceilometer/+bug/1301371
            result = set()
            for ignored, data in gen:
                flatten_result, s, meters, md = hbase_utils.deserialize_entry(
                    data)
                for m in meters:
                    if limit and len(result) >= limit:
                        return
                    _m_rts, m_source, name, m_type, unit = m[0]
                    meter_dict = {'name': name,
                                  'type': m_type,
                                  'unit': unit,
                                  'resource_id': flatten_result['resource_id'],
                                  'project_id': flatten_result['project_id'],
                                  'user_id': flatten_result['user_id']}
                    frozen_meter = frozenset(meter_dict.items())
                    if frozen_meter in result:
                        continue
                    result.add(frozen_meter)
                    meter_dict.update({'source': m_source
                                       if m_source else None})

                    yield models.Meter(**meter_dict)
예제 #11
0
def search_results_to_meters(results, limit=None, unique=False):
    """Transforms results of the search to the Meter instances."""

    if unique:
        meter_names = set()
    count = 0

    for record in results['hits']['hits']:
        for meter_name, specials in six.iteritems(record['_source']['meters']):
            meter_name = urllib.unquote(meter_name)
            if limit and count >= limit:
                return
            else:
                count += 1
            if unique:
                if meter_name in meter_names:
                    continue
                else:
                    meter_names.add(meter_name)
                    yield models.Meter(name=unquote(meter_name),
                                       type=specials['type'],
                                       unit=specials.get('unit', ''),
                                       resource_id=None,
                                       project_id=None,
                                       source=None,
                                       user_id=None)
            else:
                yield models.Meter(
                    name=unquote(meter_name),
                    type=specials['type'],
                    unit=specials.get('unit', ''),
                    resource_id=record['_id'],
                    source=record['_source']["source"],
                    project_id=record['_source'].get('project_id'),
                    user_id=record['_source'].get('user_id'),
                )
예제 #12
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery={},
                   pagination=None):
        """Return an iterable of models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional resource filter.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        :param pagination: Optional pagination query.
        """

        if pagination:
            raise NotImplementedError(_('Pagination not implemented'))
        with self.conn_pool.connection() as conn:
            resource_table = conn.table(self.RESOURCE_TABLE)
            q = make_query(metaquery=metaquery,
                           user_id=user,
                           project_id=project,
                           resource_id=resource,
                           source=source)
            LOG.debug(_("Query Resource table: %s") % q)

            gen = resource_table.scan(filter=q)

            for ignored, data in gen:
                flatten_result, s, m, md = deserialize_entry(data)
                if not m:
                    continue
                # Meter table may have only one "meter" and "source". That's
                # why only first lists element is get in this method
                name, type, unit = m[0].split("!")
                yield models.Meter(
                    name=name,
                    type=type,
                    unit=unit,
                    resource_id=flatten_result['resource_id'],
                    project_id=flatten_result['project_id'],
                    source=s[0] if s else None,
                    user_id=flatten_result['user_id'],
                )
예제 #13
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery={}):
        """Return an iterable of models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional resource filter.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        """
        q, ignored, ignored = make_query(user=user,
                                         project=project,
                                         resource=resource,
                                         source=source,
                                         require_meter=False)
        LOG.debug("q: %s" % q)
        # TODO implement metaquery support
        if len(metaquery) > 0:
            raise NotImplementedError('metaquery not implemented')

        gen = self.resource.scan(filter=q)

        for ignored, data in gen:
            # Meter columns are stored like this:
            # "m_{counter_name}|{counter_type}|{counter_unit}" => "1"
            # where 'm' is a prefix (m for meter), value is always set to 1
            meter = None
            for m in data:
                if m.startswith('f:m_'):
                    meter = m
                    break
            if meter is None:
                continue
            name, type, unit = meter[4:].split("!")
            yield models.Meter(
                name=name,
                type=type,
                unit=unit,
                resource_id=data['f:resource_id'],
                project_id=data['f:project_id'],
                user_id=data['f:user_id'],
            )
예제 #14
0
    def get_meters(user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery={}):
        """Return an iterable of api_models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional ID of the resource.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        """
        session = sqlalchemy_session.get_session()
        query = session.query(Resource)
        if user is not None:
            query = query.filter(Resource.user_id == user)
        if source is not None:
            query = query.filter(Resource.sources.any(id=source))
        if resource:
            query = query.filter(Resource.id == resource)
        if project is not None:
            query = query.filter(Resource.project_id == project)
        query = query.options(
            sqlalchemy_session.sqlalchemy.orm.joinedload('meters'))
        if metaquery:
            raise NotImplementedError('metaquery not implemented')

        for resource in query.all():
            meter_names = set()
            for meter in resource.meters:
                if meter.counter_name in meter_names:
                    continue
                meter_names.add(meter.counter_name)
                yield api_models.Meter(
                    name=meter.counter_name,
                    type=meter.counter_type,
                    unit=meter.counter_unit,
                    resource_id=resource.id,
                    project_id=resource.project_id,
                    source=resource.sources[0].id,
                    user_id=resource.user_id,
                )
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery=None,
                   pagination=None):
        """Return an iterable of api_models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional ID of the resource.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        :param pagination: Optional pagination query.
        """

        if pagination:
            raise ceilometer.NotImplementedError('Pagination not implemented')

        s_filter = storage.SampleFilter(user=user,
                                        project=project,
                                        source=source,
                                        metaquery=metaquery,
                                        resource=resource)

        # NOTE(gordc): get latest sample of each meter/resource. we do not
        #              filter here as we want to filter only on latest record.
        session = self._engine_facade.get_session()
        subq = session.query(func.max(models.Sample.id).label('id')).join(
            models.Resource,
            models.Resource.internal_id == models.Sample.resource_id).group_by(
                models.Sample.meter_id, models.Resource.resource_id)
        if resource:
            subq = subq.filter(models.Resource.resource_id == resource)
        subq = subq.subquery()

        # get meter details for samples.
        query_sample = (session.query(
            models.Sample.meter_id, models.Meter.name, models.Meter.type,
            models.Meter.unit, models.Resource.resource_id,
            models.Resource.project_id,
            models.Resource.source_id, models.Resource.user_id).join(
                subq, subq.c.id == models.Sample.id).join(
                    models.Meter,
                    models.Meter.id == models.Sample.meter_id).join(
                        models.Resource, models.Resource.internal_id ==
                        models.Sample.resource_id))

        query_sample = make_query_from_filter(session,
                                              query_sample,
                                              s_filter,
                                              require_meter=False)

        if project is None:
            query_sample = (query_sample.limit(
                cfg.CONF.sqlalchemy.max_sample_limit))

        for row in query_sample.all():
            yield api_models.Meter(name=row.name,
                                   type=row.type,
                                   unit=row.unit,
                                   resource_id=row.resource_id,
                                   project_id=row.project_id,
                                   source=row.source_id,
                                   user_id=row.user_id)
예제 #16
0
    def get_meters(self,
                   user=None,
                   project=None,
                   resource=None,
                   source=None,
                   metaquery=None,
                   pagination=None):
        """Return an iterable of api_models.Meter instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param resource: Optional ID of the resource.
        :param source: Optional source filter.
        :param metaquery: Optional dict with metadata to match on.
        :param pagination: Optional pagination query.
        """

        if pagination:
            raise NotImplementedError('Pagination not implemented')

        metaquery = metaquery or {}

        def _apply_filters(query):
            # TODO(gordc) this should be merged with make_query_from_filter
            for column, value in [(models.Sample.resource_id, resource),
                                  (models.Sample.user_id, user),
                                  (models.Sample.project_id, project),
                                  (models.Sample.source_id, source)]:
                if value:
                    query = query.filter(column == value)
            if metaquery:
                query = apply_metaquery_filter(session, query, metaquery)
            return query

        session = self._engine_facade.get_session()

        # sample_subq is used to reduce sample records
        # by selecting a record for each (resource_id, meter_id).
        # max() is used to choice a sample record, so the latest record
        # is selected for each (resource_id, meter_id).
        sample_subq = session.query(
            func.max(models.Sample.id).label('id'))\
            .group_by(models.Sample.meter_id, models.Sample.resource_id)
        sample_subq = sample_subq.subquery()

        # SELECT sample.* FROM sample INNER JOIN
        #  (SELECT max(sample.id) AS id FROM sample
        #   GROUP BY sample.resource_id, sample.meter_id) AS anon_2
        # ON sample.id = anon_2.id
        query_sample = session.query(models.MeterSample).\
            join(sample_subq, models.MeterSample.id == sample_subq.c.id)
        query_sample = _apply_filters(query_sample)

        for sample in query_sample.all():
            yield api_models.Meter(name=sample.counter_name,
                                   type=sample.counter_type,
                                   unit=sample.counter_unit,
                                   resource_id=sample.resource_id,
                                   project_id=sample.project_id,
                                   source=sample.source_id,
                                   user_id=sample.user_id)