Implement user-api
This implements the blueprint user-api for version 1 of the API. The ACL checks now don't return access denied on non-admin users. All requests without a <project> in the URL limit their scope to the tenant contained into X-Tenant-Id. All request with a <project> in the URL returns 404 if the <project> specified is different than the one from X-Tenant-Id. Change-Id: If1ec55fa491ea5de30036ce7ed75d0f28e925457 Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
parent
ade5b235b0
commit
0ba1ec0da9
@ -17,7 +17,6 @@
|
||||
# under the License.
|
||||
"""Set up the ACL to acces the API server."""
|
||||
|
||||
import flask
|
||||
from ceilometer import policy
|
||||
|
||||
import keystoneclient.middleware.auth_token as auth_token
|
||||
@ -37,14 +36,12 @@ def install(app, conf):
|
||||
app.wsgi_app = auth_token.AuthProtocol(app.wsgi_app,
|
||||
conf=conf,
|
||||
)
|
||||
app.before_request(check)
|
||||
return app
|
||||
|
||||
|
||||
def check():
|
||||
"""Check application access."""
|
||||
headers = flask.request.headers
|
||||
def get_limited_to_project(headers):
|
||||
"""Return the tenant the request should be limited to."""
|
||||
if not policy.check_is_admin(headers.get('X-Roles', "").split(","),
|
||||
headers.get('X-Tenant-Id'),
|
||||
headers.get('X-Tenant-Name')):
|
||||
return "Access denied", 401
|
||||
return headers.get('X-Tenant-Id')
|
||||
|
@ -85,6 +85,8 @@ from ceilometer.openstack.common import timeutils
|
||||
|
||||
from ceilometer import storage
|
||||
|
||||
from ceilometer.api.v1 import acl
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
@ -105,6 +107,13 @@ def _get_metaquery(args):
|
||||
for (k, v) in args.iteritems()
|
||||
if k.startswith('metadata.'))
|
||||
|
||||
|
||||
def check_authorized_project(project):
|
||||
authorized_project = acl.get_limited_to_project(flask.request.headers)
|
||||
if authorized_project and authorized_project != project:
|
||||
flask.abort(404)
|
||||
|
||||
|
||||
## APIs for working with meters.
|
||||
|
||||
|
||||
@ -114,7 +123,9 @@ def list_meters_all():
|
||||
:param metadata.<key> match on the metadata within the resource. (optional)
|
||||
"""
|
||||
rq = flask.request
|
||||
meters = rq.storage_conn.get_meters(metaquery=_get_metaquery(rq.args))
|
||||
meters = rq.storage_conn.get_meters(
|
||||
project=acl.get_limited_to_project(rq.headers),
|
||||
metaquery=_get_metaquery(rq.args))
|
||||
return flask.jsonify(meters=list(meters))
|
||||
|
||||
|
||||
@ -126,8 +137,10 @@ def list_meters_by_resource(resource):
|
||||
:param metadata.<key> match on the metadata within the resource. (optional)
|
||||
"""
|
||||
rq = flask.request
|
||||
meters = rq.storage_conn.get_meters(resource=resource,
|
||||
metaquery=_get_metaquery(rq.args))
|
||||
meters = rq.storage_conn.get_meters(
|
||||
resource=resource,
|
||||
project=acl.get_limited_to_project(rq.headers),
|
||||
metaquery=_get_metaquery(rq.args))
|
||||
return flask.jsonify(meters=list(meters))
|
||||
|
||||
|
||||
@ -139,8 +152,10 @@ def list_meters_by_user(user):
|
||||
:param metadata.<key> match on the metadata within the resource. (optional)
|
||||
"""
|
||||
rq = flask.request
|
||||
meters = rq.storage_conn.get_meters(user=user,
|
||||
metaquery=_get_metaquery(rq.args))
|
||||
meters = rq.storage_conn.get_meters(
|
||||
user=user,
|
||||
project=acl.get_limited_to_project(rq.headers),
|
||||
metaquery=_get_metaquery(rq.args))
|
||||
return flask.jsonify(meters=list(meters))
|
||||
|
||||
|
||||
@ -151,9 +166,12 @@ def list_meters_by_project(project):
|
||||
:param project: The ID of the owning project.
|
||||
:param metadata.<key> match on the metadata within the resource. (optional)
|
||||
"""
|
||||
check_authorized_project(project)
|
||||
|
||||
rq = flask.request
|
||||
meters = rq.storage_conn.get_meters(project=project,
|
||||
metaquery=_get_metaquery(rq.args))
|
||||
meters = rq.storage_conn.get_meters(
|
||||
project=project,
|
||||
metaquery=_get_metaquery(rq.args))
|
||||
return flask.jsonify(meters=list(meters))
|
||||
|
||||
|
||||
@ -165,8 +183,10 @@ def list_meters_by_source(source):
|
||||
:param metadata.<key> match on the metadata within the resource. (optional)
|
||||
"""
|
||||
rq = flask.request
|
||||
meters = rq.storage_conn.get_meters(source=source,
|
||||
metaquery=_get_metaquery(rq.args))
|
||||
meters = rq.storage_conn.get_meters(
|
||||
source=source,
|
||||
project=acl.get_limited_to_project(rq.headers),
|
||||
metaquery=_get_metaquery(rq.args))
|
||||
return flask.jsonify(meters=list(meters))
|
||||
|
||||
|
||||
@ -201,6 +221,7 @@ def list_resources_by_project(project):
|
||||
:type end_timestamp: ISO date in UTC
|
||||
:param metadata.<key> match on the metadata within the resource. (optional)
|
||||
"""
|
||||
check_authorized_project(project)
|
||||
return _list_resources(project=project)
|
||||
|
||||
|
||||
@ -216,7 +237,8 @@ def list_all_resources():
|
||||
:type end_timestamp: ISO date in UTC
|
||||
:param metadata.<key> match on the metadata within the resource. (optional)
|
||||
"""
|
||||
return _list_resources()
|
||||
return _list_resources(
|
||||
project=acl.get_limited_to_project(flask.request.headers))
|
||||
|
||||
|
||||
@blueprint.route('/sources/<source>')
|
||||
@ -242,7 +264,10 @@ def list_resources_by_source(source):
|
||||
:type end_timestamp: ISO date in UTC
|
||||
:param metadata.<key> match on the metadata within the resource. (optional)
|
||||
"""
|
||||
return _list_resources(source=source)
|
||||
return _list_resources(
|
||||
source=source,
|
||||
project=acl.get_limited_to_project(flask.request.headers),
|
||||
)
|
||||
|
||||
|
||||
@blueprint.route('/users/<user>/resources')
|
||||
@ -258,7 +283,10 @@ def list_resources_by_user(user):
|
||||
:type end_timestamp: ISO date in UTC
|
||||
:param metadata.<key> match on the metadata within the resource. (optional)
|
||||
"""
|
||||
return _list_resources(user=user)
|
||||
return _list_resources(
|
||||
user=user,
|
||||
project=acl.get_limited_to_project(flask.request.headers),
|
||||
)
|
||||
|
||||
|
||||
## APIs for working with users.
|
||||
@ -267,7 +295,13 @@ def list_resources_by_user(user):
|
||||
def _list_users(source=None):
|
||||
"""Return a list of user names.
|
||||
"""
|
||||
users = flask.request.storage_conn.get_users(source=source)
|
||||
# TODO(jd) it might be better to return the real list of users that are
|
||||
# belonging to the project, but that's not provided by the storage
|
||||
# drivers for now
|
||||
if acl.get_limited_to_project(flask.request.headers):
|
||||
users = [flask.request.headers.get('X-User-id')]
|
||||
else:
|
||||
users = flask.request.storage_conn.get_users(source=source)
|
||||
return flask.jsonify(users=list(users))
|
||||
|
||||
|
||||
@ -294,7 +328,18 @@ def list_users_by_source(source):
|
||||
def _list_projects(source=None):
|
||||
"""Return a list of project names.
|
||||
"""
|
||||
projects = flask.request.storage_conn.get_projects(source=source)
|
||||
project = acl.get_limited_to_project(flask.request.headers)
|
||||
if project:
|
||||
if source:
|
||||
if project in flask.request.storage_conn.get_projects(
|
||||
source=source):
|
||||
projects = [project]
|
||||
else:
|
||||
projects = []
|
||||
else:
|
||||
projects = [project]
|
||||
else:
|
||||
projects = flask.request.storage_conn.get_projects(source=source)
|
||||
return flask.jsonify(projects=list(projects))
|
||||
|
||||
|
||||
@ -334,7 +379,7 @@ def _list_events(meter,
|
||||
start=q_ts['start_timestamp'],
|
||||
end=q_ts['end_timestamp'],
|
||||
metaquery=_get_metaquery(flask.request.args),
|
||||
)
|
||||
)
|
||||
events = list(flask.request.storage_conn.get_raw_events(f))
|
||||
jsonified = flask.jsonify(events=events)
|
||||
if request_wants_html():
|
||||
@ -361,6 +406,7 @@ def list_events_by_project(project, meter):
|
||||
(optional)
|
||||
:type end_timestamp: ISO date in UTC
|
||||
"""
|
||||
check_authorized_project(project)
|
||||
return _list_events(project=project,
|
||||
meter=meter,
|
||||
)
|
||||
@ -379,9 +425,11 @@ def list_events_by_resource(resource, meter):
|
||||
(optional)
|
||||
:type end_timestamp: ISO date in UTC
|
||||
"""
|
||||
return _list_events(resource=resource,
|
||||
meter=meter,
|
||||
)
|
||||
return _list_events(
|
||||
resource=resource,
|
||||
meter=meter,
|
||||
project=acl.get_limited_to_project(flask.request.headers),
|
||||
)
|
||||
|
||||
|
||||
@blueprint.route('/sources/<source>/meters/<meter>')
|
||||
@ -397,9 +445,11 @@ def list_events_by_source(source, meter):
|
||||
(optional)
|
||||
:type end_timestamp: ISO date in UTC
|
||||
"""
|
||||
return _list_events(source=source,
|
||||
meter=meter,
|
||||
)
|
||||
return _list_events(
|
||||
source=source,
|
||||
meter=meter,
|
||||
project=acl.get_limited_to_project(flask.request.headers),
|
||||
)
|
||||
|
||||
|
||||
@blueprint.route('/users/<user>/meters/<meter>')
|
||||
@ -415,9 +465,11 @@ def list_events_by_user(user, meter):
|
||||
(optional)
|
||||
:type end_timestamp: ISO date in UTC
|
||||
"""
|
||||
return _list_events(user=user,
|
||||
meter=meter,
|
||||
)
|
||||
return _list_events(
|
||||
user=user,
|
||||
meter=meter,
|
||||
project=acl.get_limited_to_project(flask.request.headers),
|
||||
)
|
||||
|
||||
|
||||
## APIs for working with meter calculations.
|
||||
@ -475,11 +527,13 @@ def compute_duration_by_resource(resource, meter):
|
||||
|
||||
# Query the database for the interval of timestamps
|
||||
# within the desired range.
|
||||
f = storage.EventFilter(meter=meter,
|
||||
resource=resource,
|
||||
start=q_ts['query_start'],
|
||||
end=q_ts['query_end'],
|
||||
)
|
||||
f = storage.EventFilter(
|
||||
meter=meter,
|
||||
project=acl.get_limited_to_project(flask.request.headers),
|
||||
resource=resource,
|
||||
start=q_ts['query_start'],
|
||||
end=q_ts['query_end'],
|
||||
)
|
||||
min_ts, max_ts = flask.request.storage_conn.get_event_interval(f)
|
||||
|
||||
# "Clamp" the timestamps we return to the original time
|
||||
@ -533,11 +587,13 @@ def compute_max_resource_volume(resource, meter):
|
||||
q_ts = _get_query_timestamps(flask.request.args)
|
||||
|
||||
# Query the database for the max volume
|
||||
f = storage.EventFilter(meter=meter,
|
||||
resource=resource,
|
||||
start=q_ts['query_start'],
|
||||
end=q_ts['query_end'],
|
||||
)
|
||||
f = storage.EventFilter(
|
||||
meter=meter,
|
||||
project=acl.get_limited_to_project(flask.request.headers),
|
||||
resource=resource,
|
||||
start=q_ts['query_start'],
|
||||
end=q_ts['query_end'],
|
||||
)
|
||||
# TODO(sberler): do we want to return an error if the resource
|
||||
# does not exist?
|
||||
results = list(flask.request.storage_conn.get_volume_max(f))
|
||||
@ -564,11 +620,13 @@ def compute_resource_volume_sum(resource, meter):
|
||||
q_ts = _get_query_timestamps(flask.request.args)
|
||||
|
||||
# Query the database for the max volume
|
||||
f = storage.EventFilter(meter=meter,
|
||||
resource=resource,
|
||||
start=q_ts['query_start'],
|
||||
end=q_ts['query_end'],
|
||||
)
|
||||
f = storage.EventFilter(
|
||||
meter=meter,
|
||||
project=acl.get_limited_to_project(flask.request.headers),
|
||||
resource=resource,
|
||||
start=q_ts['query_start'],
|
||||
end=q_ts['query_end'],
|
||||
)
|
||||
# TODO(sberler): do we want to return an error if the resource
|
||||
# does not exist?
|
||||
results = list(flask.request.storage_conn.get_volume_sum(f))
|
||||
@ -592,6 +650,8 @@ def compute_project_volume_max(project, meter):
|
||||
:param search_offset: Number of minutes before and
|
||||
after start and end timestamps to query.
|
||||
"""
|
||||
check_authorized_project(project)
|
||||
|
||||
q_ts = _get_query_timestamps(flask.request.args)
|
||||
|
||||
f = storage.EventFilter(meter=meter,
|
||||
@ -624,6 +684,8 @@ def compute_project_volume_sum(project, meter):
|
||||
:param search_offset: Number of minutes before and
|
||||
after start and end timestamps to query.
|
||||
"""
|
||||
check_authorized_project(project)
|
||||
|
||||
q_ts = _get_query_timestamps(flask.request.args)
|
||||
|
||||
f = storage.EventFilter(meter=meter,
|
||||
|
@ -97,7 +97,7 @@ def make_query_from_filter(event_filter, require_meter=True):
|
||||
|
||||
if event_filter.user:
|
||||
q['user_id'] = event_filter.user
|
||||
elif event_filter.project:
|
||||
if event_filter.project:
|
||||
q['project_id'] = event_filter.project
|
||||
|
||||
if event_filter.meter:
|
||||
|
@ -52,18 +52,20 @@ class TestBase(db_test_base.TestBase):
|
||||
def attach_storage_connection():
|
||||
flask.request.storage_conn = self.conn
|
||||
|
||||
def get(self, path, **kwds):
|
||||
def get(self, path, headers=None, **kwds):
|
||||
if kwds:
|
||||
query = path + '?' + urllib.urlencode(kwds)
|
||||
else:
|
||||
query = path
|
||||
rv = self.test_app.get(query)
|
||||
try:
|
||||
data = json.loads(rv.data)
|
||||
except ValueError:
|
||||
print 'RAW DATA:', rv
|
||||
raise
|
||||
return data
|
||||
rv = self.test_app.get(query, headers=headers)
|
||||
if rv.status_code == 200 and rv.content_type == 'application/json':
|
||||
try:
|
||||
data = json.loads(rv.data)
|
||||
except ValueError:
|
||||
print 'RAW DATA:', rv
|
||||
raise
|
||||
return data
|
||||
return rv
|
||||
|
||||
|
||||
class FunctionalTest(unittest.TestCase):
|
||||
|
@ -1,63 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
#
|
||||
# Copyright © 2012 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Author: Julien Danjou <julien@danjou.info>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""Test ACL."""
|
||||
|
||||
from ceilometer.tests import api as tests_api
|
||||
from ceilometer.api.v1 import acl
|
||||
|
||||
|
||||
class TestAPIACL(tests_api.TestBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAPIACL, self).setUp()
|
||||
acl.install(self.app, {})
|
||||
|
||||
def test_non_authenticated(self):
|
||||
with self.app.test_request_context('/'):
|
||||
self.app.preprocess_request()
|
||||
self.assertEqual(self.test_app.get().status_code, 401)
|
||||
|
||||
def test_authenticated_wrong_role(self):
|
||||
with self.app.test_request_context('/', headers={
|
||||
"X-Roles": "Member",
|
||||
"X-Tenant-Name": "foobar",
|
||||
"X-Tenant-Id": "bc23a9d531064583ace8f67dad60f6bb",
|
||||
}):
|
||||
self.app.preprocess_request()
|
||||
self.assertEqual(self.test_app.get().status_code, 401)
|
||||
|
||||
# FIXME(dhellmann): This test is not properly looking at the tenant
|
||||
# info. The status code returned is the expected value, but it
|
||||
# is not clear why.
|
||||
#
|
||||
# def test_authenticated_wrong_tenant(self):
|
||||
# with self.app.test_request_context('/', headers={
|
||||
# "X-Roles": "admin",
|
||||
# "X-Tenant-Name": "foobar",
|
||||
# "X-Tenant-Id": "bc23a9d531064583ace8f67dad60f6bb",
|
||||
# }):
|
||||
# self.app.preprocess_request()
|
||||
# self.assertEqual(self.test_app.get().status_code, 401)
|
||||
|
||||
def test_authenticated(self):
|
||||
with self.app.test_request_context('/', headers={
|
||||
"X-Roles": "admin",
|
||||
"X-Tenant-Name": "admin",
|
||||
"X-Tenant-Id": "bc23a9d531064583ace8f67dad60f6bb",
|
||||
}):
|
||||
self.assertEqual(self.app.preprocess_request(), None)
|
@ -3,6 +3,7 @@
|
||||
# Copyright © 2012 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
|
||||
# Julien Danjou <julien@danjou.info>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
@ -85,6 +86,18 @@ class TestListEvents(tests_api.TestBase):
|
||||
data = self.get('/projects/project1/meters/instance')
|
||||
self.assertEquals(2, len(data['events']))
|
||||
|
||||
def test_by_project_non_admin(self):
|
||||
data = self.get('/projects/project1/meters/instance',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project1"})
|
||||
self.assertEquals(2, len(data['events']))
|
||||
|
||||
def test_by_project_wrong_tenant(self):
|
||||
resp = self.get('/projects/project1/meters/instance',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "this-is-my-project"})
|
||||
self.assertEquals(404, resp.status_code)
|
||||
|
||||
def test_by_project_with_timestamps(self):
|
||||
data = self.get('/projects/project1/meters/instance',
|
||||
start_timestamp=datetime.datetime(2012, 7, 2, 10, 42))
|
||||
@ -98,6 +111,18 @@ class TestListEvents(tests_api.TestBase):
|
||||
data = self.get('/resources/resource-id/meters/instance')
|
||||
self.assertEquals(2, len(data['events']))
|
||||
|
||||
def test_by_resource_non_admin(self):
|
||||
data = self.get('/resources/resource-id-alternate/meters/instance',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project2"})
|
||||
self.assertEquals(1, len(data['events']))
|
||||
|
||||
def test_by_resource_some_tenant(self):
|
||||
data = self.get('/resources/resource-id/meters/instance',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project2"})
|
||||
self.assertEquals(0, len(data['events']))
|
||||
|
||||
def test_empty_source(self):
|
||||
data = self.get('/sources/no-such-source/meters/instance')
|
||||
self.assertEquals({'events': []}, data)
|
||||
@ -106,6 +131,12 @@ class TestListEvents(tests_api.TestBase):
|
||||
data = self.get('/sources/source1/meters/instance')
|
||||
self.assertEquals(3, len(data['events']))
|
||||
|
||||
def test_by_source_non_admin(self):
|
||||
data = self.get('/sources/source1/meters/instance',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project2"})
|
||||
self.assertEquals(1, len(data['events']))
|
||||
|
||||
def test_by_source_with_timestamps(self):
|
||||
data = self.get('/sources/source1/meters/instance',
|
||||
end_timestamp=datetime.datetime(2012, 7, 2, 10, 42))
|
||||
@ -119,6 +150,18 @@ class TestListEvents(tests_api.TestBase):
|
||||
data = self.get('/users/user-id/meters/instance')
|
||||
self.assertEquals(2, len(data['events']))
|
||||
|
||||
def test_by_user_non_admin(self):
|
||||
data = self.get('/users/user-id/meters/instance',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project1"})
|
||||
self.assertEquals(2, len(data['events']))
|
||||
|
||||
def test_by_user_wrong_tenant(self):
|
||||
data = self.get('/users/user-id/meters/instance',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project2"})
|
||||
self.assertEquals(0, len(data['events']))
|
||||
|
||||
def test_by_user_with_timestamps(self):
|
||||
data = self.get('/users/user-id/meters/instance',
|
||||
start_timestamp=datetime.datetime(2012, 7, 2, 10, 41),
|
||||
@ -130,12 +173,33 @@ class TestListEvents(tests_api.TestBase):
|
||||
data = self.get('%s?metadata.tag=self.counter2' % q)
|
||||
self.assertEquals(1, len(data['events']))
|
||||
|
||||
def test_metaquery1_wrong_tenant(self):
|
||||
q = '/sources/source1/meters/instance'
|
||||
data = self.get('%s?metadata.tag=self.counter2' % q,
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project1"})
|
||||
self.assertEquals(0, len(data['events']))
|
||||
|
||||
def test_metaquery2(self):
|
||||
q = '/sources/source1/meters/instance'
|
||||
data = self.get('%s?metadata.tag=self.counter' % q)
|
||||
self.assertEquals(2, len(data['events']))
|
||||
|
||||
def test_metaquery2_non_admin(self):
|
||||
q = '/sources/source1/meters/instance'
|
||||
data = self.get('%s?metadata.tag=self.counter' % q,
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project1"})
|
||||
self.assertEquals(2, len(data['events']))
|
||||
|
||||
def test_metaquery3(self):
|
||||
q = '/sources/source1/meters/instance'
|
||||
data = self.get('%s?metadata.display_name=test-server' % q)
|
||||
self.assertEquals(3, len(data['events']))
|
||||
|
||||
def test_metaquery3_with_project(self):
|
||||
q = '/sources/source1/meters/instance'
|
||||
data = self.get('%s?metadata.display_name=test-server' % q,
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project2"})
|
||||
self.assertEquals(1, len(data['events']))
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Copyright 2012 Red Hat, Inc.
|
||||
#
|
||||
# Author: Angus Salkeld <asalkeld@redhat.com>
|
||||
# Julien Danjou <julien@danjou.info>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
@ -115,6 +116,18 @@ class TestListMeters(tests_api.TestBase):
|
||||
set(['meter.test',
|
||||
'meter.mine']))
|
||||
|
||||
def test_list_meters_non_admin(self):
|
||||
data = self.get('/meters',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEquals(2, len(data['meters']))
|
||||
self.assertEquals(set(r['resource_id'] for r in data['meters']),
|
||||
set(['resource-id',
|
||||
'resource-id2']))
|
||||
self.assertEquals(set(r['name'] for r in data['meters']),
|
||||
set(['meter.test',
|
||||
'meter.mine']))
|
||||
|
||||
def test_with_resource(self):
|
||||
data = self.get('/resources/resource-id/meters')
|
||||
ids = set(r['name'] for r in data['meters'])
|
||||
@ -128,6 +141,14 @@ class TestListMeters(tests_api.TestBase):
|
||||
'resource-id3',
|
||||
'resource-id4']), ids)
|
||||
|
||||
def test_with_source_non_admin(self):
|
||||
data = self.get('/sources/test_list_resources/meters',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id2"})
|
||||
ids = set(r['resource_id'] for r in data['meters'])
|
||||
self.assertEquals(set(['resource-id3',
|
||||
'resource-id4']), ids)
|
||||
|
||||
def test_with_source_non_existent(self):
|
||||
data = self.get('/sources/test_list_resources_dont_exist/meters')
|
||||
self.assertEquals(data['meters'], [])
|
||||
@ -141,6 +162,23 @@ class TestListMeters(tests_api.TestBase):
|
||||
rids = set(r['resource_id'] for r in data['meters'])
|
||||
self.assertEquals(set(['resource-id', 'resource-id2']), rids)
|
||||
|
||||
def test_with_user_non_admin(self):
|
||||
data = self.get('/users/user-id/meters',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
nids = set(r['name'] for r in data['meters'])
|
||||
self.assertEquals(set(['meter.mine', 'meter.test']), nids)
|
||||
|
||||
rids = set(r['resource_id'] for r in data['meters'])
|
||||
self.assertEquals(set(['resource-id', 'resource-id2']), rids)
|
||||
|
||||
def test_with_user_wrong_tenant(self):
|
||||
data = self.get('/users/user-id/meters',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project666"})
|
||||
|
||||
self.assertEquals(data['meters'], [])
|
||||
|
||||
def test_with_user_non_existent(self):
|
||||
data = self.get('/users/user-id-foobar123/meters')
|
||||
self.assertEquals(data['meters'], [])
|
||||
@ -150,6 +188,19 @@ class TestListMeters(tests_api.TestBase):
|
||||
ids = set(r['resource_id'] for r in data['meters'])
|
||||
self.assertEquals(set(['resource-id3', 'resource-id4']), ids)
|
||||
|
||||
def test_with_project_non_admin(self):
|
||||
data = self.get('/projects/project-id2/meters',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id2"})
|
||||
ids = set(r['resource_id'] for r in data['meters'])
|
||||
self.assertEquals(set(['resource-id3', 'resource-id4']), ids)
|
||||
|
||||
def test_with_project_wrong_tenant(self):
|
||||
data = self.get('/projects/project-id2/meters',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEqual(data.status_code, 404)
|
||||
|
||||
def test_with_project_non_existent(self):
|
||||
data = self.get('/projects/jd-was-here/meters')
|
||||
self.assertEquals(data['meters'], [])
|
||||
@ -158,6 +209,30 @@ class TestListMeters(tests_api.TestBase):
|
||||
data = self.get('/meters?metadata.tag=self.counter')
|
||||
self.assertEquals(1, len(data['meters']))
|
||||
|
||||
def test_metaquery1_non_admin(self):
|
||||
data = self.get('/meters?metadata.tag=self.counter',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEquals(1, len(data['meters']))
|
||||
|
||||
def test_metaquery1_wrong_tenant(self):
|
||||
data = self.get('/meters?metadata.tag=self.counter',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-666"})
|
||||
self.assertEquals(0, len(data['meters']))
|
||||
|
||||
def test_metaquery2(self):
|
||||
data = self.get('/meters?metadata.tag=four.counter')
|
||||
self.assertEquals(1, len(data['meters']))
|
||||
|
||||
def test_metaquery2_non_admin(self):
|
||||
data = self.get('/meters?metadata.tag=four.counter',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id2"})
|
||||
self.assertEquals(1, len(data['meters']))
|
||||
|
||||
def test_metaquery2_non_admin(self):
|
||||
data = self.get('/meters?metadata.tag=four.counter',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-666"})
|
||||
self.assertEquals(0, len(data['meters']))
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Copyright © 2012 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
|
||||
# Julien Danjou <julien@danjou.info>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
@ -30,13 +31,17 @@ from ceilometer.tests import api as tests_api
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestListProjects(tests_api.TestBase):
|
||||
class TestListEmptyProjects(tests_api.TestBase):
|
||||
|
||||
def test_empty(self):
|
||||
data = self.get('/projects')
|
||||
self.assertEquals({'projects': []}, data)
|
||||
|
||||
def test_projects(self):
|
||||
|
||||
class TestListProjects(tests_api.TestBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestListProjects, self).setUp()
|
||||
counter1 = counter.Counter(
|
||||
'instance',
|
||||
'cumulative',
|
||||
@ -73,45 +78,22 @@ class TestListProjects(tests_api.TestBase):
|
||||
)
|
||||
self.conn.record_metering_data(msg2)
|
||||
|
||||
def test_projects(self):
|
||||
data = self.get('/projects')
|
||||
self.assertEquals(['project-id', 'project-id2'], data['projects'])
|
||||
|
||||
def test_with_source(self):
|
||||
counter1 = counter.Counter(
|
||||
'instance',
|
||||
'cumulative',
|
||||
1,
|
||||
'user-id',
|
||||
'project-id',
|
||||
'resource-id',
|
||||
timestamp=datetime.datetime(2012, 7, 2, 10, 40),
|
||||
resource_metadata={'display_name': 'test-server',
|
||||
'tag': 'self.counter',
|
||||
}
|
||||
)
|
||||
msg = meter.meter_message_from_counter(counter1,
|
||||
cfg.CONF.metering_secret,
|
||||
'test_list_users',
|
||||
)
|
||||
self.conn.record_metering_data(msg)
|
||||
|
||||
counter2 = counter.Counter(
|
||||
'instance',
|
||||
'cumulative',
|
||||
1,
|
||||
'user-id2',
|
||||
'project-id2',
|
||||
'resource-id-alternate',
|
||||
timestamp=datetime.datetime(2012, 7, 2, 10, 41),
|
||||
resource_metadata={'display_name': 'test-server',
|
||||
'tag': 'self.counter2',
|
||||
}
|
||||
)
|
||||
msg2 = meter.meter_message_from_counter(counter2,
|
||||
cfg.CONF.metering_secret,
|
||||
'not-test',
|
||||
)
|
||||
self.conn.record_metering_data(msg2)
|
||||
|
||||
data = self.get('/sources/test_list_users/projects')
|
||||
def test_projects_non_admin(self):
|
||||
data = self.get('/projects',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEquals(['project-id'], data['projects'])
|
||||
|
||||
def test_with_source(self):
|
||||
data = self.get('/sources/test_list_users/projects')
|
||||
self.assertEquals(['project-id2'], data['projects'])
|
||||
|
||||
def test_with_source_non_admin(self):
|
||||
data = self.get('/sources/test_list_users/projects',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id2"})
|
||||
self.assertEquals(['project-id2'], data['projects'])
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Copyright © 2012 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
|
||||
# Julien Danjou <julien@danjou.info>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
@ -100,6 +101,15 @@ class TestListResources(tests_api.TestBase):
|
||||
'resource-id-alternate',
|
||||
'resource-id2']))
|
||||
|
||||
def test_list_resources_non_admin(self):
|
||||
data = self.get('/resources',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEquals(2, len(data['resources']))
|
||||
self.assertEquals(set(r['resource_id'] for r in data['resources']),
|
||||
set(['resource-id',
|
||||
'resource-id-alternate']))
|
||||
|
||||
def test_list_resources_with_timestamps(self):
|
||||
data = self.get('/resources',
|
||||
start_timestamp=datetime.datetime(
|
||||
@ -110,6 +120,17 @@ class TestListResources(tests_api.TestBase):
|
||||
set(['resource-id-alternate',
|
||||
'resource-id2']))
|
||||
|
||||
def test_list_resources_with_timestamps_non_admin(self):
|
||||
data = self.get('/resources',
|
||||
start_timestamp=datetime.datetime(
|
||||
2012, 7, 2, 10, 41).isoformat(),
|
||||
end_timestamp=datetime.datetime(
|
||||
2012, 7, 2, 10, 43).isoformat(),
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEquals(set(r['resource_id'] for r in data['resources']),
|
||||
set(['resource-id-alternate']))
|
||||
|
||||
def test_with_source(self):
|
||||
data = self.get('/sources/test_list_resources/resources')
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
@ -117,6 +138,14 @@ class TestListResources(tests_api.TestBase):
|
||||
'resource-id2',
|
||||
'resource-id-alternate']), ids)
|
||||
|
||||
def test_with_source_non_admin(self):
|
||||
data = self.get('/sources/test_list_resources/resources',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(['resource-id',
|
||||
'resource-id-alternate']), ids)
|
||||
|
||||
def test_with_source_with_timestamps(self):
|
||||
data = self.get('/sources/test_list_resources/resources',
|
||||
start_timestamp=datetime.datetime(
|
||||
@ -127,6 +156,17 @@ class TestListResources(tests_api.TestBase):
|
||||
self.assertEquals(set(['resource-id2',
|
||||
'resource-id-alternate']), ids)
|
||||
|
||||
def test_with_source_with_timestamps_non_admin(self):
|
||||
data = self.get('/sources/test_list_resources/resources',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"},
|
||||
start_timestamp=datetime.datetime(
|
||||
2012, 7, 2, 10, 41).isoformat(),
|
||||
end_timestamp=datetime.datetime(
|
||||
2012, 7, 2, 10, 43).isoformat())
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(['resource-id-alternate']), ids)
|
||||
|
||||
def test_with_source_non_existent(self):
|
||||
data = self.get('/sources/test_list_resources_dont_exist/resources')
|
||||
self.assertEquals(data['resources'], [])
|
||||
@ -136,6 +176,20 @@ class TestListResources(tests_api.TestBase):
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(['resource-id', 'resource-id-alternate']), ids)
|
||||
|
||||
def test_with_user_non_admin(self):
|
||||
data = self.get('/users/user-id/resources',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(['resource-id', 'resource-id-alternate']), ids)
|
||||
|
||||
def test_with_user_wrong_tenant(self):
|
||||
data = self.get('/users/user-id/resources',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-jd"})
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(), ids)
|
||||
|
||||
def test_with_user_with_timestamps(self):
|
||||
data = self.get('/users/user-id/resources',
|
||||
start_timestamp=datetime.datetime(
|
||||
@ -145,6 +199,17 @@ class TestListResources(tests_api.TestBase):
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(), ids)
|
||||
|
||||
def test_with_user_with_timestamps_non_admin(self):
|
||||
data = self.get('/users/user-id/resources',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"},
|
||||
start_timestamp=datetime.datetime(
|
||||
2012, 7, 2, 10, 42).isoformat(),
|
||||
end_timestamp=datetime.datetime(
|
||||
2012, 7, 2, 10, 42).isoformat())
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(), ids)
|
||||
|
||||
def test_with_user_non_existent(self):
|
||||
data = self.get('/users/user-id-foobar123/resources')
|
||||
self.assertEquals(data['resources'], [])
|
||||
@ -154,6 +219,13 @@ class TestListResources(tests_api.TestBase):
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(['resource-id', 'resource-id-alternate']), ids)
|
||||
|
||||
def test_with_project_non_admin(self):
|
||||
data = self.get('/projects/project-id/resources',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(['resource-id', 'resource-id-alternate']), ids)
|
||||
|
||||
def test_with_project_with_timestamp(self):
|
||||
data = self.get('/projects/project-id/resources',
|
||||
start_timestamp=datetime.datetime(
|
||||
@ -163,6 +235,17 @@ class TestListResources(tests_api.TestBase):
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(['resource-id']), ids)
|
||||
|
||||
def test_with_project_with_timestamp_non_admin(self):
|
||||
data = self.get('/projects/project-id/resources',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"},
|
||||
start_timestamp=datetime.datetime(
|
||||
2012, 7, 2, 10, 40).isoformat(),
|
||||
end_timestamp=datetime.datetime(
|
||||
2012, 7, 2, 10, 41).isoformat())
|
||||
ids = set(r['resource_id'] for r in data['resources'])
|
||||
self.assertEquals(set(['resource-id']), ids)
|
||||
|
||||
def test_with_project_non_existent(self):
|
||||
data = self.get('/projects/jd-was-here/resources')
|
||||
self.assertEquals(data['resources'], [])
|
||||
@ -172,7 +255,21 @@ class TestListResources(tests_api.TestBase):
|
||||
data = self.get('%s?metadata.display_name=test-server' % q)
|
||||
self.assertEquals(3, len(data['resources']))
|
||||
|
||||
def test_metaquery1_non_admin(self):
|
||||
q = '/sources/test_list_resources/resources'
|
||||
data = self.get('%s?metadata.display_name=test-server' % q,
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEquals(2, len(data['resources']))
|
||||
|
||||
def test_metaquery2(self):
|
||||
q = '/sources/test_list_resources/resources'
|
||||
data = self.get('%s?metadata.tag=self.counter4' % q)
|
||||
self.assertEquals(1, len(data['resources']))
|
||||
|
||||
def test_metaquery2_non_admin(self):
|
||||
q = '/sources/test_list_resources/resources'
|
||||
data = self.get('%s?metadata.tag=self.counter4' % q,
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEquals(1, len(data['resources']))
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Copyright © 2012 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
|
||||
# Julien Danjou <julien@danjou.info>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
@ -30,53 +31,18 @@ from ceilometer.tests import api as tests_api
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestListUsers(tests_api.TestBase):
|
||||
class TestListEmptyUsers(tests_api.TestBase):
|
||||
|
||||
def test_empty(self):
|
||||
data = self.get('/users')
|
||||
self.assertEquals({'users': []}, data)
|
||||
|
||||
def test_users(self):
|
||||
counter1 = counter.Counter(
|
||||
'instance',
|
||||
'cumulative',
|
||||
1,
|
||||
'user-id',
|
||||
'project-id',
|
||||
'resource-id',
|
||||
timestamp=datetime.datetime(2012, 7, 2, 10, 40),
|
||||
resource_metadata={'display_name': 'test-server',
|
||||
'tag': 'self.counter',
|
||||
}
|
||||
)
|
||||
msg = meter.meter_message_from_counter(counter1,
|
||||
cfg.CONF.metering_secret,
|
||||
'test_list_users',
|
||||
)
|
||||
self.conn.record_metering_data(msg)
|
||||
|
||||
counter2 = counter.Counter(
|
||||
'instance',
|
||||
'cumulative',
|
||||
1,
|
||||
'user-id2',
|
||||
'project-id',
|
||||
'resource-id-alternate',
|
||||
timestamp=datetime.datetime(2012, 7, 2, 10, 41),
|
||||
resource_metadata={'display_name': 'test-server',
|
||||
'tag': 'self.counter2',
|
||||
}
|
||||
)
|
||||
msg2 = meter.meter_message_from_counter(counter2,
|
||||
cfg.CONF.metering_secret,
|
||||
'test_list_users',
|
||||
)
|
||||
self.conn.record_metering_data(msg2)
|
||||
class TestListUsers(tests_api.TestBase):
|
||||
|
||||
data = self.get('/users')
|
||||
self.assertEquals(['user-id', 'user-id2'], data['users'])
|
||||
def setUp(self):
|
||||
super(TestListUsers, self).setUp()
|
||||
|
||||
def test_with_source(self):
|
||||
counter1 = counter.Counter(
|
||||
'instance',
|
||||
'cumulative',
|
||||
@ -113,5 +79,24 @@ class TestListUsers(tests_api.TestBase):
|
||||
)
|
||||
self.conn.record_metering_data(msg2)
|
||||
|
||||
def test_users(self):
|
||||
data = self.get('/users')
|
||||
self.assertEquals(['user-id', 'user-id2'], data['users'])
|
||||
|
||||
def test_users_non_admin(self):
|
||||
data = self.get('/users',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-User-Id": "user-id",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEquals(['user-id'], data['users'])
|
||||
|
||||
def test_with_source(self):
|
||||
data = self.get('/sources/test_list_users/users')
|
||||
self.assertEquals(['user-id'], data['users'])
|
||||
|
||||
def test_with_source_non_admin(self):
|
||||
data = self.get('/sources/test_list_users/users',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-User-Id": "user-id",
|
||||
"X-Tenant-Id": "project-id"})
|
||||
self.assertEquals(['user-id'], data['users'])
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Copyright © 2012 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Author: Steven Berler <steven.berler@dreamhost.com>
|
||||
# Julien Danjou <julien@danjou.info>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
@ -60,6 +61,18 @@ class TestMaxProjectVolume(tests_api.TestBase):
|
||||
expected = {'volume': 7}
|
||||
assert data == expected
|
||||
|
||||
def test_no_time_bounds_non_admin(self):
|
||||
data = self.get('/projects/project1/meters/volume.size/volume/max',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project1"})
|
||||
self.assertEqual(data, {'volume': 7})
|
||||
|
||||
def test_no_time_bounds_wrong_tenant(self):
|
||||
resp = self.get('/projects/project1/meters/volume.size/volume/max',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "?"})
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
|
||||
def test_start_timestamp(self):
|
||||
data = self.get('/projects/project1/meters/volume.size/volume/max',
|
||||
start_timestamp='2012-09-25T11:30:00')
|
||||
|
@ -60,6 +60,18 @@ class TestMaxResourceVolume(tests_api.TestBase):
|
||||
expected = {'volume': 7}
|
||||
assert data == expected
|
||||
|
||||
def test_no_time_bounds_non_admin(self):
|
||||
data = self.get('/resources/resource-id/meters/volume.size/volume/max',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project1"})
|
||||
self.assertEqual(data, {'volume': 7})
|
||||
|
||||
def test_no_time_bounds_wrong_tenant(self):
|
||||
data = self.get('/resources/resource-id/meters/volume.size/volume/max',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "??"})
|
||||
self.assertEqual(data, {'volume': None})
|
||||
|
||||
def test_start_timestamp(self):
|
||||
data = self.get('/resources/resource-id/meters/volume.size/volume/max',
|
||||
start_timestamp='2012-09-25T11:30:00')
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Copyright © 2012 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Author: Steven Berler <steven.berler@dreamhost.com>
|
||||
# Julien Danjou <julien@danjou.info>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
@ -60,6 +61,18 @@ class TestSumProjectVolume(tests_api.TestBase):
|
||||
expected = {'volume': 5 + 6 + 7}
|
||||
assert data == expected
|
||||
|
||||
def test_no_time_bounds_non_admin(self):
|
||||
data = self.get('/projects/project1/meters/volume.size/volume/sum',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project1"})
|
||||
self.assertEqual(data, {'volume': 5 + 6 + 7})
|
||||
|
||||
def test_no_time_bounds_wrong_tenant(self):
|
||||
resp = self.get('/projects/project1/meters/volume.size/volume/sum',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "???"})
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
|
||||
def test_start_timestamp(self):
|
||||
data = self.get('/projects/project1/meters/volume.size/volume/sum',
|
||||
start_timestamp='2012-09-25T11:30:00')
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Copyright © 2012 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
|
||||
# Julien Danjou <julien@danjou.info>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
@ -60,6 +61,18 @@ class TestSumResourceVolume(tests_api.TestBase):
|
||||
expected = {'volume': 5 + 6 + 7}
|
||||
assert data == expected
|
||||
|
||||
def test_no_time_bounds_non_admin(self):
|
||||
data = self.get('/resources/resource-id/meters/volume.size/volume/sum',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "project1"})
|
||||
self.assertEqual(data, {'volume': 5 + 6 + 7})
|
||||
|
||||
def test_no_time_bounds_wrong_tenant(self):
|
||||
data = self.get('/resources/resource-id/meters/volume.size/volume/sum',
|
||||
headers={"X-Roles": "Member",
|
||||
"X-Tenant-Id": "?"})
|
||||
self.assertEqual(data, {'volume': None})
|
||||
|
||||
def test_start_timestamp(self):
|
||||
data = self.get('/resources/resource-id/meters/volume.size/volume/sum',
|
||||
start_timestamp='2012-09-25T11:30:00')
|
||||
|
Loading…
x
Reference in New Issue
Block a user