def get_resources(user=None,
                      project=None,
                      source=None,
                      start_timestamp=None,
                      start_timestamp_op=None,
                      end_timestamp=None,
                      end_timestamp_op=None,
                      metaquery={},
                      resource=None):
        """Return an iterable of api_models.Resource instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param source: Optional source filter.
        :param start_timestamp: Optional modified timestamp start range.
        :param start_timestamp_op: Optonal start time operator, like gt, ge.
        :param end_timestamp: Optional modified timestamp end range.
        :param end_timestamp_op: Optional end time operator, like lt, le.
        :param metaquery: Optional dict with metadata to match on.
        :param resource: Optional resource filter.
        """
        session = sqlalchemy_session.get_session()
        query = session.query(Meter, ).group_by(Meter.resource_id)
        if user is not None:
            query = query.filter(Meter.user_id == user)
        if source is not None:
            query = query.filter(Meter.sources.any(id=source))
        if start_timestamp:
            if start_timestamp_op == 'gt':
                query = query.filter(Meter.timestamp > start_timestamp)
            else:
                query = query.filter(Meter.timestamp >= start_timestamp)
        if end_timestamp:
            if end_timestamp_op == 'le':
                query = query.filter(Meter.timestamp <= end_timestamp)
            else:
                query = query.filter(Meter.timestamp < end_timestamp)
        if project is not None:
            query = query.filter(Meter.project_id == project)
        if resource is not None:
            query = query.filter(Meter.resource_id == resource)
        if metaquery:
            raise NotImplementedError('metaquery not implemented')

        for meter in query.all():
            yield api_models.Resource(
                resource_id=meter.resource_id,
                project_id=meter.project_id,
                source=meter.sources[0].id,
                user_id=meter.user_id,
                metadata=meter.resource_metadata,
                meter=[
                    api_models.ResourceMeter(
                        counter_name=m.counter_name,
                        counter_type=m.counter_type,
                        counter_unit=m.counter_unit,
                    ) for m in meter.resource.meters
                ],
            )
示例#2
0
    def get_resources(self, user=None, project=None, source=None,
                      start_timestamp=None, end_timestamp=None,
                      metaquery={}, resource=None):
        """Return an iterable of models.Resource instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param source: Optional source filter.
        :param start_timestamp: Optional modified timestamp start range.
        :param end_timestamp: Optional modified timestamp end range.
        :param metaquery: Optional dict with metadata to match on.
        :param resource: Optional resource filter.
        """
        q = {}
        if user is not None:
            q['user_id'] = user
        if project is not None:
            q['project_id'] = project
        if source is not None:
            q['source'] = source
        if resource is not None:
            q['resource_id'] = resource
        # Add resource_ prefix so it matches the field in the db
        q.update(dict(('resource_' + k, v)
                      for (k, v) in metaquery.iteritems()))

        # FIXME(dhellmann): This may not perform very well,
        # but doing any better will require changing the database
        # schema and that will need more thought than I have time
        # to put into it today.
        if start_timestamp or end_timestamp:
            # Look for resources matching the above criteria and with
            # samples in the time range we care about, then change the
            # resource query to return just those resources by id.
            ts_range = make_timestamp_range(start_timestamp, end_timestamp)
            if ts_range:
                q['timestamp'] = ts_range

        # FIXME(jd): We should use self.db.meter.group() and not use the
        # resource collection, but that's not supported by MIM, so it's not
        # easily testable yet. Since it was bugged before anyway, it's still
        # better for now.
        resource_ids = self.db.meter.find(q).distinct('resource_id')
        q = {'_id': {'$in': resource_ids}}
        for resource in self.db.resource.find(q):
            yield models.Resource(
                resource_id=resource['_id'],
                project_id=resource['project_id'],
                user_id=resource['user_id'],
                metadata=resource['metadata'],
                meter=[
                    models.ResourceMeter(
                        counter_name=meter['counter_name'],
                        counter_type=meter['counter_type'],
                        counter_unit=meter['counter_unit'],
                    )
                    for meter in resource['meter']
                ],
            )
示例#3
0
 def test_get_resources(self):
     resources = list(self.conn.get_resources())
     assert len(resources) == 4
     for resource in resources:
         if resource.resource_id != 'resource-id':
             continue
         assert resource.resource_id == 'resource-id'
         assert resource.project_id == 'project-id'
         assert resource.user_id == 'user-id'
         assert resource.metadata['display_name'] == 'test-server'
         self.assertIn(models.ResourceMeter('instance', 'cumulative', ''),
                       resource.meter)
         break
     else:
         assert False, 'Never found resource-id'
示例#4
0
    def get_resources(self,
                      user=None,
                      project=None,
                      source=None,
                      start_timestamp=None,
                      end_timestamp=None,
                      metaquery={}):
        """Return an iterable of models.Resource instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param source: Optional source filter.
        :param start_timestamp: Optional modified timestamp start range.
        :param end_timestamp: Optional modified timestamp end range.
        """
        q, start_row, end_row = make_query(user=user,
                                           project=project,
                                           source=source,
                                           start=start_timestamp,
                                           end=end_timestamp,
                                           require_meter=False)
        LOG.debug("q: %s" % q)
        # TODO implement metaquery support
        if len(metaquery) > 0:
            raise NotImplementedError('metaquery not implemented')

        resource_ids = {}
        g = self.meter.scan(filter=q, row_start=start_row, row_stop=end_row)
        for ignored, data in g:
            resource_ids[data['f:resource_id']] = data['f:resource_id']

        q = make_query(user=user,
                       project=project,
                       source=source,
                       query_only=True,
                       require_meter=False)
        LOG.debug("q: %s" % q)
        for resource_id, data in self.resource.rows(resource_ids):
            yield models.Resource(
                resource_id=resource_id,
                project_id=data['f:project_id'],
                user_id=data['f:user_id'],
                metadata=json.loads(data['f:metadata']),
                meter=[
                    models.ResourceMeter(*(m[4:].split("!"))) for m in data
                    if m.startswith('f:m_')
                ],
            )
示例#5
0
        def make_resource(data):
            """Transform HBase fields to Resource model."""
            # convert HBase metadata e.g. f:r_display_name to display_name
            data['f:metadata'] = dict((k[4:], v) for k, v in data.iteritems()
                                      if k.startswith('f:r_'))

            return models.Resource(
                resource_id=data['f:resource_id'],
                project_id=data['f:project_id'],
                source=data['f:source'],
                user_id=data['f:user_id'],
                metadata=data['f:metadata'],
                meter=[
                    models.ResourceMeter(*(m[4:].split("!"))) for m in data
                    if m.startswith('f:m_')
                ],
            )
示例#6
0
        def make_resource(data, first_ts, last_ts, meter_refs):
            """Transform HBase fields to Resource model."""
            # convert HBase metadata e.g. f:r_display_name to display_name
            data['f:metadata'] = _metadata_from_document(data)

            return models.Resource(
                resource_id=data['f:resource_id'],
                first_sample_timestamp=first_ts,
                last_sample_timestamp=last_ts,
                project_id=data['f:project_id'],
                source=data['f:source'],
                user_id=data['f:user_id'],
                metadata=data['f:metadata'],
                meter=[
                    models.ResourceMeter(*(m.split("!"))) for m in meter_refs
                ],
            )
示例#7
0
 def test_get_resources(self):
     msgs_sources = [msg['source'] for msg in self.msgs]
     resources = list(self.conn.get_resources())
     self.assertEqual(len(resources), 9)
     for resource in resources:
         if resource.resource_id != 'resource-id':
             continue
         self.assertEqual(resource.first_sample_timestamp,
                          None)
         self.assertEqual(resource.last_sample_timestamp,
                          None)
         assert resource.resource_id == 'resource-id'
         assert resource.project_id == 'project-id'
         self.assertIn(resource.source, msgs_sources)
         assert resource.user_id == 'user-id'
         assert resource.metadata['display_name'] == 'test-server'
         self.assertIn(models.ResourceMeter('instance', 'cumulative', ''),
                       resource.meter)
         break
     else:
         assert False, 'Never found resource-id'
示例#8
0
    def get_resources(self,
                      user=None,
                      project=None,
                      source=None,
                      start_timestamp=None,
                      start_timestamp_op=None,
                      end_timestamp=None,
                      end_timestamp_op=None,
                      metaquery={},
                      resource=None,
                      limit=None,
                      marker_pairs=None,
                      sort_key=None,
                      sort_dir=None):
        """Return an iterable of models.Resource instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param source: Optional source filter.
        :param start_timestamp: Optional modified timestamp start range.
        :param start_timestamp_op: Optional start time operator, like gt, ge.
        :param end_timestamp: Optional modified timestamp end range.
        :param end_timestamp_op: Optional end time operator, like lt, le.
        :param metaquery: Optional dict with metadata to match on.
        :param resource: Optional resource filter.
        :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).
        """

        if marker_pairs:
            raise NotImplementedError(
                "Cannot use marker pairs in resource listing, not implemented")

        q = {}
        if user is not None:
            q['user_id'] = user
        if project is not None:
            q['project_id'] = project
        if source is not None:
            q['source'] = source
        if resource is not None:
            q['resource_id'] = resource
        # Add resource_ prefix so it matches the field in the db
        q.update(dict(
            ('resource_' + k, v) for (k, v) in metaquery.iteritems()))

        # FIXME(dhellmann): This may not perform very well,
        # but doing any better will require changing the database
        # schema and that will need more thought than I have time
        # to put into it today.
        if start_timestamp or end_timestamp:
            # Look for resources matching the above criteria and with
            # samples in the time range we care about, then change the
            # resource query to return just those resources by id.
            ts_range = make_timestamp_range(start_timestamp, end_timestamp,
                                            start_timestamp_op,
                                            end_timestamp_op)
            if ts_range:
                q['timestamp'] = ts_range

        sort_keys = base._handle_sort_key('resource', sort_key)
        sort_instruction, query = self._build_paginate_query(
            None, sort_keys, sort_dir)
        q.update(query)

        aggregate = self.db.meter.aggregate([
            {
                "$match": q
            },
            {
                "$sort": dict(sort_instruction)
            },
            {
                "$group": {
                    "_id": "$resource_id",
                    "user_id": {
                        "$first": "$user_id"
                    },
                    "project_id": {
                        "$first": "$project_id"
                    },
                    "source": {
                        "$first": "$source"
                    },
                    "first_sample_timestamp": {
                        "$min": "$timestamp"
                    },
                    "last_sample_timestamp": {
                        "$max": "$timestamp"
                    },
                    "metadata": {
                        "$first": "$resource_metadata"
                    },
                    "meters_name": {
                        "$push": "$counter_name"
                    },
                    "meters_type": {
                        "$push": "$counter_type"
                    },
                    "meters_unit": {
                        "$push": "$counter_unit"
                    },
                }
            },
        ])

        for result in aggregate['result']:
            if limit is not None:
                if limit == 0:
                    break
                limit -= 1
            yield models.Resource(
                resource_id=result['_id'],
                user_id=result['user_id'],
                project_id=result['project_id'],
                first_sample_timestamp=result['first_sample_timestamp'],
                last_sample_timestamp=result['last_sample_timestamp'],
                source=result['source'],
                metadata=result['metadata'],
                meter=[
                    models.ResourceMeter(
                        counter_name=m_n,
                        counter_type=m_t,
                        counter_unit=m_u,
                    ) for m_n, m_u, m_t in
                    zip(result['meters_name'], result['meters_unit'],
                        result['meters_type'])
                ],
            )
示例#9
0
    def get_resources(self, user=None, project=None, source=None,
                      start_timestamp=None, start_timestamp_op=None,
                      end_timestamp=None, end_timestamp_op=None,
                      metaquery={}, resource=None, pagination=None):
        """Return an iterable of models.Resource instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param source: Optional source filter.
        :param start_timestamp: Optional modified timestamp start range.
        :param start_timestamp_op: Optional start time operator, like gt, ge.
        :param end_timestamp: Optional modified timestamp end range.
        :param end_timestamp_op: Optional end time operator, like lt, le.
        :param metaquery: Optional dict with metadata to match on.
        :param resource: Optional resource filter.
        :param pagination: Optional pagination query.
        """
        if pagination:
            raise NotImplementedError(_('Pagination not implemented'))

        q = {}
        if user is not None:
            q['user_id'] = user
        if project is not None:
            q['project_id'] = project
        if source is not None:
            q['source'] = source
        if resource is not None:
            q['resource_id'] = resource
        # Add resource_ prefix so it matches the field in the db
        q.update(dict(('resource_' + k, v)
                      for (k, v) in metaquery.iteritems()))

        if start_timestamp or end_timestamp:
            # Look for resources matching the above criteria and with
            # samples in the time range we care about, then change the
            # resource query to return just those resources by id.
            ts_range = make_timestamp_range(start_timestamp, end_timestamp,
                                            start_timestamp_op,
                                            end_timestamp_op)
            if ts_range:
                q['timestamp'] = ts_range

        sort_keys = base._handle_sort_key('resource', 'timestamp')
        sort_keys.insert(0, 'resource_id')
        sort_instructions = self._build_sort_instructions(sort_keys=sort_keys,
                                                          sort_dir='desc')
        resource = lambda x: x['resource_id']
        meters = self.db.meter.find(q, sort=sort_instructions)
        for resource_id, r_meters in itertools.groupby(meters, key=resource):
            resource_meters = []
            # Because we have to know first/last timestamp, and we need a full
            # list of references to the resource's meters, we need a tuple
            # here.
            r_meters = tuple(r_meters)
            for meter in r_meters:
                resource_meters.append(models.ResourceMeter(
                    counter_name=meter['counter_name'],
                    counter_type=meter['counter_type'],
                    counter_unit=meter.get('counter_unit', ''))
                )
            latest_meter = r_meters[0]
            last_ts = latest_meter['timestamp']
            first_ts = r_meters[-1]['timestamp']

            yield models.Resource(resource_id=latest_meter['resource_id'],
                                  project_id=latest_meter['project_id'],
                                  first_sample_timestamp=first_ts,
                                  last_sample_timestamp=last_ts,
                                  source=latest_meter['source'],
                                  user_id=latest_meter['user_id'],
                                  metadata=latest_meter['resource_metadata'],
                                  meter=resource_meters)
示例#10
0
    def get_resources(user=None,
                      project=None,
                      source=None,
                      start_timestamp=None,
                      start_timestamp_op=None,
                      end_timestamp=None,
                      end_timestamp_op=None,
                      metaquery={},
                      resource=None,
                      pagination=None):
        """Return an iterable of api_models.Resource instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param source: Optional source filter.
        :param start_timestamp: Optional modified timestamp start range.
        :param start_timestamp_op: Optonal start time operator, like gt, ge.
        :param end_timestamp: Optional modified timestamp end range.
        :param end_timestamp_op: Optional end time operator, like lt, le.
        :param metaquery: Optional dict with metadata to match on.
        :param resource: Optional resource filter.
        :param pagination: Optional pagination query.
        """

        # We probably want to raise these early, since we don't know from here
        # if they will be handled. We don't want extra wait or work for it to
        # just fail.
        if pagination:
            raise NotImplementedError(_('Pagination not implemented'))

        # (thomasm) We need to get the max timestamp first, since that's the
        # most accurate. We also need to filter down in the subquery to
        # constrain what we have to JOIN on later.
        session = sqlalchemy_session.get_session()

        ts_subquery = session.query(
            Meter.resource_id,
            func.max(Meter.timestamp).label("max_ts"),
            func.min(Meter.timestamp).label("min_ts")).group_by(
                Meter.resource_id)

        # Here are the basic 'eq' operation filters for the sample data.
        for column, value in [(Meter.resource_id, resource),
                              (Meter.user_id, user),
                              (Meter.project_id, project)]:
            if value:
                ts_subquery = ts_subquery.filter(column == value)

        if source:
            ts_subquery = ts_subquery.filter(Meter.sources.any(id=source))

        if metaquery:
            ts_subquery = apply_metaquery_filter(session, ts_subquery,
                                                 metaquery)

        # Here we limit the samples being used to a specific time period,
        # if requested.
        if start_timestamp:
            if start_timestamp_op == 'gt':
                ts_subquery = ts_subquery.filter(
                    Meter.timestamp > start_timestamp)
            else:
                ts_subquery = ts_subquery.filter(
                    Meter.timestamp >= start_timestamp)
        if end_timestamp:
            if end_timestamp_op == 'le':
                ts_subquery = ts_subquery.filter(
                    Meter.timestamp <= end_timestamp)
            else:
                ts_subquery = ts_subquery.filter(
                    Meter.timestamp < end_timestamp)
        ts_subquery = ts_subquery.subquery()

        # Now we need to get the max Meter.id out of the leftover results, to
        # break any ties.
        agg_subquery = session.query(
            func.max(Meter.id).label("max_id"), ts_subquery).filter(
                Meter.resource_id == ts_subquery.c.resource_id,
                Meter.timestamp == ts_subquery.c.max_ts).group_by(
                    ts_subquery.c.resource_id, ts_subquery.c.max_ts,
                    ts_subquery.c.min_ts).subquery()

        query = session.query(
            Meter, agg_subquery.c.min_ts,
            agg_subquery.c.max_ts).filter(Meter.id == agg_subquery.c.max_id)

        for meter, first_ts, last_ts in query.all():
            yield api_models.Resource(
                resource_id=meter.resource_id,
                project_id=meter.project_id,
                first_sample_timestamp=first_ts,
                last_sample_timestamp=last_ts,
                source=meter.sources[0].id,
                user_id=meter.user_id,
                metadata=meter.resource_metadata,
                meter=[
                    api_models.ResourceMeter(
                        counter_name=m.counter_name,
                        counter_type=m.counter_type,
                        counter_unit=m.counter_unit,
                    ) for m in meter.resource.meters
                ],
            )
示例#11
0
    def get_resources(self, user=None, project=None, source=None,
                      start_timestamp=None, start_timestamp_op=None,
                      end_timestamp=None, end_timestamp_op=None,
                      metaquery={}, resource=None, limit=None,
                      marker_pairs=None, sort_key=None, sort_dir=None):
        """Return an iterable of models.Resource instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param source: Optional source filter.
        :param start_timestamp: Optional modified timestamp start range.
        :param start_timestamp_op: Optional start time operator, like gt, ge.
        :param end_timestamp: Optional modified timestamp end range.
        :param end_timestamp_op: Optional end time operator, like lt, le.
        :param metaquery: Optional dict with metadata to match on.
        :param resource: Optional resource filter.
        :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 source is not None:
            q['source'] = source
        if resource is not None:
            q['resource_id'] = resource
        # Add resource_ prefix so it matches the field in the db
        q.update(dict(('resource_' + k, v)
                      for (k, v) in metaquery.iteritems()))

        # FIXME(dhellmann): This may not perform very well,
        # but doing any better will require changing the database
        # schema and that will need more thought than I have time
        # to put into it today.
        if start_timestamp or end_timestamp:
            # Look for resources matching the above criteria and with
            # samples in the time range we care about, then change the
            # resource query to return just those resources by id.
            ts_range = make_timestamp_range(start_timestamp, end_timestamp,
                                            start_timestamp_op,
                                            end_timestamp_op)
            if ts_range:
                q['timestamp'] = ts_range

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

        # FIXME(jd): We should use self.db.meter.group() and not use the
        # resource collection, but that's not supported by MIM, so it's not
        # easily testable yet. Since it was bugged before anyway, it's still
        # better for now.
        resource_ids = self.db.meter.find(q).distinct('resource_id')
        q = {'_id': {'$in': resource_ids}}
        for resource in self.paginate_query(q, self.db.resource, limit=limit,
                                            marker=marker, sort_keys=sort_keys,
                                            sort_dir=sort_dir):
            yield models.Resource(
                resource_id=resource['_id'],
                project_id=resource['project_id'],
                source=resource['source'],
                user_id=resource['user_id'],
                metadata=resource['metadata'],
                meter=[
                    models.ResourceMeter(
                        counter_name=meter['counter_name'],
                        counter_type=meter['counter_type'],
                        counter_unit=meter.get('counter_unit', ''),
                    )
                    for meter in resource['meter']
                ],
            )
示例#12
0
    def get_resources(self, user=None, project=None, source=None,
                      start_timestamp=None, start_timestamp_op=None,
                      end_timestamp=None, end_timestamp_op=None,
                      metaquery={}, resource=None, pagination=None):
        """Return an iterable of models.Resource instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param source: Optional source filter.
        :param start_timestamp: Optional modified timestamp start range.
        :param start_timestamp_op: Optional start time operator, like gt, ge.
        :param end_timestamp: Optional modified timestamp end range.
        :param end_timestamp_op: Optional end time operator, like lt, le.
        :param metaquery: Optional dict with metadata to match on.
        :param resource: Optional resource filter.
        :param pagination: Optional pagination query.
        """
        if pagination:
            raise NotImplementedError(_('Pagination not implemented'))

        q = {}
        if user is not None:
            q['user_id'] = user
        if project is not None:
            q['project_id'] = project
        if source is not None:
            q['source'] = source
        if resource is not None:
            q['resource_id'] = resource
        # Add resource_ prefix so it matches the field in the db
        q.update(dict(('resource_' + k, v)
                      for (k, v) in metaquery.iteritems()))

        # FIXME(dhellmann): This may not perform very well,
        # but doing any better will require changing the database
        # schema and that will need more thought than I have time
        # to put into it today.
        if start_timestamp or end_timestamp:
            # Look for resources matching the above criteria and with
            # samples in the time range we care about, then change the
            # resource query to return just those resources by id.
            ts_range = make_timestamp_range(start_timestamp, end_timestamp,
                                            start_timestamp_op,
                                            end_timestamp_op)
            if ts_range:
                q['timestamp'] = ts_range

        sort_keys = base._handle_sort_key('resource')
        sort_instructions = self._build_sort_instructions(sort_keys)[0]

        aggregate = self.db.meter.aggregate([
            {"$match": q},
            {"$sort": dict(sort_instructions)},
            {"$group": {
                "_id": "$resource_id",
                "user_id": {"$first": "$user_id"},
                "project_id": {"$first": "$project_id"},
                "source": {"$first": "$source"},
                "first_sample_timestamp": {"$min": "$timestamp"},
                "last_sample_timestamp": {"$max": "$timestamp"},
                "metadata": {"$first": "$resource_metadata"},
                "meters_name": {"$push": "$counter_name"},
                "meters_type": {"$push": "$counter_type"},
                "meters_unit": {"$push": "$counter_unit"},
            }},
        ])

        for result in aggregate['result']:
            yield models.Resource(
                resource_id=result['_id'],
                user_id=result['user_id'],
                project_id=result['project_id'],
                first_sample_timestamp=result['first_sample_timestamp'],
                last_sample_timestamp=result['last_sample_timestamp'],
                source=result['source'],
                metadata=result['metadata'],
                meter=[
                    models.ResourceMeter(
                        counter_name=m_n,
                        counter_type=m_t,
                        counter_unit=m_u,
                    )
                    for m_n, m_u, m_t in zip(result['meters_name'],
                                             result['meters_unit'],
                                             result['meters_type'])
                ],
            )
示例#13
0
    def get_resources(self,
                      user=None,
                      project=None,
                      source=None,
                      start_timestamp=None,
                      start_timestamp_op=None,
                      end_timestamp=None,
                      end_timestamp_op=None,
                      metaquery={},
                      resource=None,
                      pagination=None):
        """Return an iterable of models.Resource instances

        :param user: Optional ID for user that owns the resource.
        :param project: Optional ID for project that owns the resource.
        :param source: Optional source filter.
        :param start_timestamp: Optional modified timestamp start range.
        :param start_timestamp_op: Optional start time operator, like gt, ge.
        :param end_timestamp: Optional modified timestamp end range.
        :param end_timestamp_op: Optional end time operator, like lt, le.
        :param metaquery: Optional dict with metadata to match on.
        :param resource: Optional resource filter.
        :param pagination: Optional pagination query.
        """

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

        q = {}
        if user is not None:
            q['user_id'] = user
        if project is not None:
            q['project_id'] = project
        if source is not None:
            q['source'] = source
        if resource is not None:
            q['resource_id'] = resource
        # Add resource_ prefix so it matches the field in the db
        q.update(dict(
            ('resource_' + k, v) for (k, v) in metaquery.iteritems()))

        if start_timestamp or end_timestamp:
            # Look for resources matching the above criteria and with
            # samples in the time range we care about, then change the
            # resource query to return just those resources by id.
            ts_range = make_timestamp_range(start_timestamp, end_timestamp,
                                            start_timestamp_op,
                                            end_timestamp_op)
            if ts_range:
                q['timestamp'] = ts_range

        # FIXME(jd): We should use self.db.meter.group() and not use the
        # resource collection, but that's not supported by MIM, so it's not
        # easily testable yet. Since it was bugged before anyway, it's still
        # better for now.
        resource_ids = self.db.meter.find(q).distinct('resource_id')
        q = {'_id': {'$in': resource_ids}}
        for resource in self.db.resource.find(q):
            yield models.Resource(
                resource_id=resource['_id'],
                project_id=resource['project_id'],
                first_sample_timestamp=None,
                last_sample_timestamp=None,
                source=resource['source'],
                user_id=resource['user_id'],
                metadata=resource['metadata'],
                meter=[
                    models.ResourceMeter(
                        counter_name=meter['counter_name'],
                        counter_type=meter['counter_type'],
                        counter_unit=meter.get('counter_unit', ''),
                    ) for meter in resource['meter']
                ],
            )