Merge "Fix to show version information from root API."
This commit is contained in:
commit
923c9c140d
|
@ -259,14 +259,11 @@ are running:
|
|||
Post-installation activities
|
||||
----------------------------
|
||||
|
||||
Run the following commands to check whether kingbird-api is serving, please
|
||||
replace $token to the token you get from "openstack token issue":
|
||||
Run the following commands to check whether kingbird-api is serving.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
openstack token issue
|
||||
curl -H "Content-Type: application/json" -H "X-Auth-Token: $token" \
|
||||
http://127.0.0.1:8118/
|
||||
curl http://127.0.0.1:8118/
|
||||
|
||||
If the response looks like following: {"versions": [{"status": "CURRENT",
|
||||
"updated": "2016-03-07", "id": "v1.0", "links": [{"href":
|
||||
|
|
|
@ -20,11 +20,13 @@ from oslo_config import cfg
|
|||
from oslo_middleware import request_id
|
||||
from oslo_service import service
|
||||
|
||||
from kingbird.common import exceptions as k_exc
|
||||
from kingbird.common import context as ctx
|
||||
from kingbird.common.i18n import _
|
||||
|
||||
|
||||
def setup_app(*args, **kwargs):
|
||||
|
||||
opts = cfg.CONF.pecan
|
||||
config = {
|
||||
'server': {
|
||||
'port': cfg.CONF.bind_port,
|
||||
|
@ -33,12 +35,15 @@ def setup_app(*args, **kwargs):
|
|||
'app': {
|
||||
'root': 'kingbird.api.controllers.root.RootController',
|
||||
'modules': ['kingbird.api'],
|
||||
"debug": opts.debug,
|
||||
"auth_enable": opts.auth_enable,
|
||||
'errors': {
|
||||
400: '/error',
|
||||
'__force_dict__': True
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pecan_config = pecan.configuration.conf_from_dict(config)
|
||||
|
||||
# app_hooks = [], hook collection will be put here later
|
||||
|
@ -48,7 +53,7 @@ def setup_app(*args, **kwargs):
|
|||
debug=False,
|
||||
wrap_app=_wrap_app,
|
||||
force_canonical=False,
|
||||
hooks=[],
|
||||
hooks=lambda: [ctx.AuthHook()],
|
||||
guess_content_type_from_ext=True
|
||||
)
|
||||
|
||||
|
@ -57,16 +62,17 @@ def setup_app(*args, **kwargs):
|
|||
|
||||
def _wrap_app(app):
|
||||
app = request_id.RequestId(app)
|
||||
if cfg.CONF.pecan.auth_enable and cfg.CONF.auth_strategy == 'keystone':
|
||||
conf = dict(cfg.CONF.keystone_authtoken)
|
||||
# Change auth decisions of requests to the app itself.
|
||||
conf.update({'delay_auth_decision': True})
|
||||
|
||||
if cfg.CONF.auth_strategy == 'noauth':
|
||||
pass
|
||||
elif cfg.CONF.auth_strategy == 'keystone':
|
||||
app = auth_token.AuthProtocol(app, {})
|
||||
# NOTE: Policy enforcement works only if Keystone
|
||||
# authentication is enabled. No support for other authentication
|
||||
# types at this point.
|
||||
return auth_token.AuthProtocol(app, conf)
|
||||
else:
|
||||
raise k_exc.InvalidConfigurationOption(
|
||||
opt_name='auth_strategy', opt_value=cfg.CONF.auth_strategy)
|
||||
|
||||
return app
|
||||
return app
|
||||
|
||||
|
||||
_launcher = None
|
||||
|
|
|
@ -25,6 +25,33 @@ global_opts = [
|
|||
default=60,
|
||||
help='Seconds between running periodic reporting tasks.'),
|
||||
]
|
||||
|
||||
# Pecan_opts
|
||||
pecan_opts = [
|
||||
cfg.StrOpt(
|
||||
'root',
|
||||
default='kingbird.api.controllers.root.RootController',
|
||||
help='Pecan root controller'
|
||||
),
|
||||
cfg.ListOpt(
|
||||
'modules',
|
||||
default=["kingbird.api"],
|
||||
help='A list of modules where pecan will search for applications.'
|
||||
),
|
||||
cfg.BoolOpt(
|
||||
'debug',
|
||||
default=False,
|
||||
help='Enables the ability to display tracebacks in the browser and'
|
||||
'interactively debug during development.'
|
||||
),
|
||||
cfg.BoolOpt(
|
||||
'auth_enable',
|
||||
default=True,
|
||||
help='Enables user authentication in pecan.'
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
# Global nova quotas for all projects
|
||||
nova_quotas = [
|
||||
cfg.IntOpt('quota_instances',
|
||||
|
@ -150,9 +177,12 @@ common_opts = [
|
|||
|
||||
scheduler_opt_group = cfg.OptGroup('scheduler',
|
||||
title='Scheduler options for periodic job')
|
||||
# The group stores Kingbird global limit for all the projects
|
||||
# The group stores Kingbird global limit for all the projects.
|
||||
default_quota_group = cfg.OptGroup(name='kingbird_global_limit',
|
||||
title='Global quota limit for all projects')
|
||||
# The group stores the pecan configurations.
|
||||
pecan_group = cfg.OptGroup(name='pecan',
|
||||
title='Pecan options')
|
||||
|
||||
cache_opt_group = cfg.OptGroup(name='cache',
|
||||
title='OpenStack Credentials')
|
||||
|
@ -164,6 +194,7 @@ def list_opts():
|
|||
yield default_quota_group.name, cinder_quotas
|
||||
yield cache_opt_group.name, cache_opts
|
||||
yield scheduler_opt_group.name, scheduler_opts
|
||||
yield pecan_group.name, pecan_opts
|
||||
yield None, global_opts
|
||||
yield None, common_opts
|
||||
|
||||
|
|
|
@ -10,12 +10,17 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pecan
|
||||
from pecan import hooks
|
||||
|
||||
from oslo_context import context as base_context
|
||||
from oslo_utils import encodeutils
|
||||
|
||||
from kingbird.common import policy
|
||||
from kingbird.db import api as db_api
|
||||
|
||||
ALLOWED_WITHOUT_AUTH = ['/', '/v1.0']
|
||||
|
||||
|
||||
class RequestContext(base_context.RequestContext):
|
||||
'''Stores information about the security context.
|
||||
|
@ -122,3 +127,21 @@ def get_service_context(**args):
|
|||
in an OpenStack cloud.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class AuthHook(hooks.PecanHook):
|
||||
def before(self, state):
|
||||
if state.request.path in ALLOWED_WITHOUT_AUTH:
|
||||
return
|
||||
req = state.request
|
||||
identity_status = req.headers.get('X-Identity-Status')
|
||||
service_identity_status = req.headers.get('X-Service-Identity-Status')
|
||||
if (identity_status == 'Confirmed' or
|
||||
service_identity_status == 'Confirmed'):
|
||||
return
|
||||
if req.headers.get('X-Auth-Token'):
|
||||
msg = 'Auth token is invalid: %s' % req.headers['X-Auth-Token']
|
||||
else:
|
||||
msg = 'Authentication required'
|
||||
msg = "Failed to validate access token: %s" % str(msg)
|
||||
pecan.abort(status_code=401, detail=msg)
|
||||
|
|
|
@ -44,10 +44,11 @@ class KingbirdQMTestJSON(base.BaseKingbirdTest):
|
|||
|
||||
def test_kingbird_put_method(self):
|
||||
new_quota = {"quota_set": {"instances": 15, "cores": 10}}
|
||||
actual_value = self.create_custom_kingbird_quota(
|
||||
response = self.create_custom_kingbird_quota(
|
||||
self.resource_ids["project_id"],
|
||||
self.resource_ids["target_project_id"],
|
||||
new_quota)
|
||||
actual_value = response.json()
|
||||
expected_value = {
|
||||
self.resource_ids["target_project_id"]: new_quota["quota_set"]
|
||||
}
|
||||
|
@ -154,8 +155,7 @@ class KingbirdQMTestJSON(base.BaseKingbirdTest):
|
|||
self.resource_ids["project_id"],
|
||||
self.resource_ids["target_project_id"],
|
||||
new_quota)
|
||||
result = eval(response).get('error').get('code')
|
||||
self.assertEqual(result, 401)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
|
||||
def test_quota_sync_for_project(self):
|
||||
# Delete custom quota if there are any for this project
|
||||
|
|
|
@ -139,7 +139,7 @@ def create_custom_kingbird_quota(token, project_id, target_project_id,
|
|||
quota_api_url)
|
||||
url_string = url_string + target_project_id
|
||||
response = requests.put(url_string, headers=headers, data=body)
|
||||
return response.text
|
||||
return response
|
||||
|
||||
|
||||
def get_custom_kingbird_quota(token, project_id, target_project_id):
|
||||
|
|
|
@ -32,11 +32,12 @@ FAKE_RESOURCE_ID = 'fake_id'
|
|||
FAKE_RESOURCE_TYPE = 'keypair'
|
||||
FAKE_TENANT = utils.UUID1
|
||||
FAKE_JOB = utils.UUID2
|
||||
FAKE_URL = '/v1.0/' + FAKE_TENANT + '/os-sync/'
|
||||
WRONG_URL = '/v1.0/wrong/os-sync/'
|
||||
FAKE_URL = '/v1.0/' + FAKE_TENANT + '/os-sync'
|
||||
WRONG_URL = '/v1.0/wrong/os-sync'
|
||||
fake_user = utils.UUID3
|
||||
FAKE_STATUS = consts.JOB_PROGRESS
|
||||
FAKE_HEADERS = {'X-Tenant-Id': FAKE_TENANT, 'X_ROLE': 'admin'}
|
||||
FAKE_HEADERS = {'X-Tenant-Id': FAKE_TENANT, 'X_ROLE': 'admin',
|
||||
'X-Identity-Status': 'Confirmed'}
|
||||
NON_ADMIN_HEADERS = {'X-Tenant-Id': FAKE_TENANT}
|
||||
|
||||
|
||||
|
|
|
@ -16,15 +16,20 @@ import mock
|
|||
import webtest
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from kingbird.api.controllers.v1 import quota_class
|
||||
from kingbird.common import config
|
||||
from kingbird.tests.unit.api import testroot
|
||||
from kingbird.tests import utils
|
||||
|
||||
config.register_options()
|
||||
OPT_GROUP_NAME = 'keystone_authtoken'
|
||||
cfg.CONF.import_group(OPT_GROUP_NAME, "keystonemiddleware.auth_token")
|
||||
FAKE_TENANT = utils.UUID1
|
||||
ADMIN_HEADERS = {'X-Tenant-Id': FAKE_TENANT, 'X_ROLE': 'admin',
|
||||
'X-Identity-Status': 'Confirmed'}
|
||||
NON_ADMIN_HEADERS = {'X-Tenant-Id': FAKE_TENANT,
|
||||
'X-Identity-Status': 'Confirmed'}
|
||||
|
||||
|
||||
class Result(object):
|
||||
|
@ -42,32 +47,29 @@ class TestQuotaClassController(testroot.KBApiTest):
|
|||
|
||||
@mock.patch.object(quota_class, 'db_api')
|
||||
def test_get_all_admin(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
result = Result('class1', 'ram', 100)
|
||||
mock_db_api.quota_class_get_all_by_name.return_value = \
|
||||
{"class_name": result.class_name,
|
||||
result.resource: result.hard_limit}
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % fake_tenant
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % FAKE_TENANT
|
||||
response = self.app.get(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual({'quota_class_set': {'id': 'class1', 'ram': 100}},
|
||||
eval(response.text))
|
||||
|
||||
def test_get_invalid_req(self):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
FAKE_HEADERS = {'X_ROLE': 'nonadmin'}
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.get, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
def test_get_invalid_req_with_admin(self):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
FAKE_HEADERS = {'X_ROLE': 'admin'}
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.get, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(quota_class, 'db_api')
|
||||
def test_put_admin(self, mock_db_api):
|
||||
|
@ -76,11 +78,10 @@ class TestQuotaClassController(testroot.KBApiTest):
|
|||
{"class_name": result.class_name,
|
||||
result.resource: result.hard_limit}
|
||||
data = {"quota_class_set": {result.resource: result.hard_limit}}
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % fake_tenant
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % FAKE_TENANT
|
||||
response = self.app.put_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'},
|
||||
headers=ADMIN_HEADERS,
|
||||
params=data)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual({'quota_class_set': {'id': 'class1', 'cores': 10}},
|
||||
|
@ -89,61 +90,47 @@ class TestQuotaClassController(testroot.KBApiTest):
|
|||
@mock.patch.object(quota_class, 'db_api')
|
||||
def test_delete_all_admin(self, mock_db_api):
|
||||
result = Result('class1', 'cores', 10)
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % fake_tenant
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % FAKE_TENANT
|
||||
mock_db_api.quota_destroy_all.return_value = result
|
||||
response = self.app.delete_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
|
||||
def test_delete_all_non_admin(self):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % fake_tenant
|
||||
try:
|
||||
self.app.delete_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant})
|
||||
except webtest.app.AppError as admin_exception:
|
||||
self.assertIn('Admin required', admin_exception.message)
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % FAKE_TENANT
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "403 *",
|
||||
self.app.delete_json, fake_url,
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
def test_delete_invalid_req_nonadmin(self):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
FAKE_HEADERS = {'X_ROLE': 'nonadmin'}
|
||||
fake_url = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.delete, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
self.app.delete, fake_url,
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
def test_delete_invalid_req_admin(self):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
FAKE_HEADERS = {'X_ROLE': 'admin'}
|
||||
fake_url = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.delete, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
self.app.delete, fake_url,
|
||||
headers=ADMIN_HEADERS)
|
||||
|
||||
def test_put_non_admin(self):
|
||||
result = Result('class1', 'cores', 10)
|
||||
data = {"quota_class_set": {result.resource: result.hard_limit}}
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % fake_tenant
|
||||
try:
|
||||
self.app.put_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant},
|
||||
params=data)
|
||||
except webtest.app.AppError as admin_exception:
|
||||
self.assertIn('Admin required', admin_exception.message)
|
||||
fake_url = '/v1.0/%s/os-quota-class-sets/class1' % FAKE_TENANT
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "403 *",
|
||||
self.app.delete, fake_url,
|
||||
headers=NON_ADMIN_HEADERS, params=data)
|
||||
|
||||
def test_put_invalid_req_non_admin(self):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
FAKE_HEADERS = {'X_ROLE': 'non-admin'}
|
||||
fake_url = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.put, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
self.app.put, fake_url,
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
def test_put_invalid_req_with_admin(self):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
FAKE_HEADERS = {'X_ROLE': 'admin'}
|
||||
fake_url = '/v1.0/dummy/os-quota-class-sets/default'
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.put, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
self.app.put, fake_url,
|
||||
headers=ADMIN_HEADERS)
|
||||
|
|
|
@ -17,15 +17,22 @@ import mock
|
|||
import webtest
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from kingbird.api.controllers import quota_manager
|
||||
from kingbird.common import config
|
||||
from kingbird.rpc import client as rpc_client
|
||||
from kingbird.tests.unit.api import testroot
|
||||
from kingbird.tests import utils
|
||||
|
||||
config.register_options()
|
||||
OPT_GROUP_NAME = 'keystone_authtoken'
|
||||
cfg.CONF.import_group(OPT_GROUP_NAME, "keystonemiddleware.auth_token")
|
||||
FAKE_TENANT = utils.UUID1
|
||||
TARGET_FAKE_TENANT = utils.UUID2
|
||||
ADMIN_HEADERS = {'X-Tenant-Id': FAKE_TENANT, 'X_ROLE': 'admin',
|
||||
'X-Identity-Status': 'Confirmed'}
|
||||
NON_ADMIN_HEADERS = {'X-Tenant-Id': TARGET_FAKE_TENANT,
|
||||
'X-Identity-Status': 'Confirmed'}
|
||||
|
||||
|
||||
class Result(object):
|
||||
|
@ -44,20 +51,18 @@ class TestQuotaManager(testroot.KBApiTest):
|
|||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_get_all_admin(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
Res = Result(fake_tenant, 'ram', 100)
|
||||
Res = Result(TARGET_FAKE_TENANT, 'ram', 100)
|
||||
mock_db_api.quota_get_all_by_project.return_value = \
|
||||
{"project_id": Res.project_id,
|
||||
Res.resource: Res.hard_limit}
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
response = self.app.get(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual({'quota_set':
|
||||
{'project_id': fake_tenant, 'ram': 100}},
|
||||
{'project_id': TARGET_FAKE_TENANT, 'ram': 100}},
|
||||
eval(response.text))
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
|
@ -65,12 +70,11 @@ class TestQuotaManager(testroot.KBApiTest):
|
|||
def test_get_default_admin(self, mock_db_api):
|
||||
mock_db_api.quota_class_get_default.return_value = \
|
||||
{'class_name': 'default'}
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/defaults'\
|
||||
% (fake_tenant)
|
||||
% (FAKE_TENANT)
|
||||
response = self.app.get(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
result = eval(response.text)
|
||||
for resource in result['quota_set']:
|
||||
|
@ -83,29 +87,25 @@ class TestQuotaManager(testroot.KBApiTest):
|
|||
expected_usage = {"ram": 10}
|
||||
mock_rpc_client().get_total_usage_for_tenant.return_value = \
|
||||
expected_usage
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s/detail'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
response = self.app.get(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual(eval(response.body), {"quota_set": expected_usage})
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_put_admin(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
Res = Result(target_fake_tenant, 'cores', 10)
|
||||
Res = Result(TARGET_FAKE_TENANT, 'cores', 10)
|
||||
mock_db_api.quota_update.return_value = Res
|
||||
data = {"quota_set": {Res.resource: Res.hard_limit}}
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
response = self.app.put_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'},
|
||||
headers=ADMIN_HEADERS,
|
||||
params=data)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual({Res.project_id: {Res.resource: Res.hard_limit}},
|
||||
|
@ -114,16 +114,14 @@ class TestQuotaManager(testroot.KBApiTest):
|
|||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_delete_admin(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
Res = Result(target_fake_tenant, 'cores', 10)
|
||||
Res = Result(TARGET_FAKE_TENANT, 'cores', 10)
|
||||
mock_db_api.quota_destroy.return_value = Res
|
||||
data = {"quota_set": [Res.resource]}
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
response = self.app.delete_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'},
|
||||
headers=ADMIN_HEADERS,
|
||||
params=data)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual({'Deleted quota limits': [Res.resource]},
|
||||
|
@ -132,101 +130,76 @@ class TestQuotaManager(testroot.KBApiTest):
|
|||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_delete_all_admin(self, mock_db_api):
|
||||
Res = Result('tenant_1', 'cores', 10)
|
||||
Res = Result(TARGET_FAKE_TENANT, 'cores', 10)
|
||||
mock_db_api.quota_destroy_all.return_value = Res
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
response = self.app.delete_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual('Deleted all quota limits for the given project',
|
||||
eval(response.text))
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
def test_quota_sync_admin(self):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s/sync'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
response = self.app.put_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant,
|
||||
'X_ROLE': 'admin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual("triggered quota sync for " + target_fake_tenant,
|
||||
self.assertEqual("triggered quota sync for " + TARGET_FAKE_TENANT,
|
||||
eval(response.text))
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
def test_put_nonadmin(self):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
Res = Result('tenant_1', 'cores', 10)
|
||||
Res = Result(TARGET_FAKE_TENANT, 'cores', 10)
|
||||
data = {"quota_set": {Res.resource: Res.hard_limit}}
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
try:
|
||||
self.app.put_json(fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant},
|
||||
params=data)
|
||||
except webtest.app.AppError as admin_exception:
|
||||
self.assertIn('Admin required', admin_exception.message)
|
||||
% (TARGET_FAKE_TENANT, FAKE_TENANT)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "403 *",
|
||||
self.app.put_json, fake_url,
|
||||
headers=NON_ADMIN_HEADERS,
|
||||
params=data)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
def test_delete_all_nonadmin(self):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
try:
|
||||
self.app.delete_json(fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant})
|
||||
except webtest.app.AppError as admin_exception:
|
||||
self.assertIn('Admin required', admin_exception.message)
|
||||
% (TARGET_FAKE_TENANT, FAKE_TENANT)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "403 *",
|
||||
self.app.delete_json, fake_url,
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
def test_delete_nonadmin(self):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
Res = Result(target_fake_tenant, 'cores', 10)
|
||||
Res = Result(TARGET_FAKE_TENANT, 'cores', 10)
|
||||
data = {"quota_set": {Res.resource: Res.hard_limit}}
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
try:
|
||||
self.app.delete_json(fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant},
|
||||
params=data)
|
||||
except webtest.app.AppError as admin_exception:
|
||||
self.assertIn('Admin required', admin_exception.message)
|
||||
% (TARGET_FAKE_TENANT, FAKE_TENANT)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "403 *",
|
||||
self.app.delete_json, fake_url,
|
||||
headers=NON_ADMIN_HEADERS,
|
||||
params=data)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
def test_quota_sync_nonadmin(self):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s/sync'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
try:
|
||||
self.app.put_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant})
|
||||
except webtest.app.AppError as admin_exception:
|
||||
self.assertIn('Admin required', admin_exception.message)
|
||||
% (TARGET_FAKE_TENANT, FAKE_TENANT)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "403 *",
|
||||
self.app.put_json, fake_url,
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_get_default_nonadmin(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/defaults'\
|
||||
% (fake_tenant)
|
||||
% (FAKE_TENANT)
|
||||
mock_db_api.quota_class_get_default.return_value = \
|
||||
{'class_name': 'default'}
|
||||
response = self.app.get(
|
||||
fake_url,
|
||||
headers={'X_TENANT_ID': fake_tenant, 'X_USER_ID': 'nonadmin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
result = eval(response.text)
|
||||
for resource in result['quota_set']:
|
||||
|
@ -236,120 +209,77 @@ class TestQuotaManager(testroot.KBApiTest):
|
|||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
def test_quota_sync_bad_request(self):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-ssdfets/%s/sync'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
try:
|
||||
self.app.post_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant,
|
||||
'X_ROLE': 'admin'})
|
||||
except webtest.app.AppError as bad_method_exception:
|
||||
self.assertIn('Bad response: 404 Not Found',
|
||||
bad_method_exception.message)
|
||||
% (TARGET_FAKE_TENANT, FAKE_TENANT)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "404 *",
|
||||
self.app.post_json, fake_url,
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_put_invalid_payload(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
Res = Result(fake_tenant, 'cores', 10)
|
||||
Res = Result(FAKE_TENANT, 'cores', 10)
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
mock_db_api.quota_update.return_value = Res
|
||||
data = {'quota': {Res.resource: Res.hard_limit}}
|
||||
try:
|
||||
self.app.put_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'},
|
||||
params=data)
|
||||
except webtest.app.AppError as invalid_payload_exception:
|
||||
self.assertIn('400 Bad Request',
|
||||
invalid_payload_exception.message)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.put_json, fake_url,
|
||||
headers=ADMIN_HEADERS, params=data)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_put_invalid_input(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
Res = Result(fake_tenant, 'cores', -10)
|
||||
Res = Result(FAKE_TENANT, 'cores', -10)
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
mock_db_api.quota_update.return_value = Res
|
||||
data = {"quota_set": {Res.resource: Res.hard_limit}}
|
||||
try:
|
||||
self.app.put_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'},
|
||||
params=data)
|
||||
except webtest.app.AppError as invalid_input_exception:
|
||||
self.assertIn('400 Bad Request',
|
||||
invalid_input_exception.message)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.put_json, fake_url,
|
||||
headers=ADMIN_HEADERS, params=data)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_delete_invalid_quota(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
Res = Result('tenant_1', 'invalid_quota', 10)
|
||||
mock_db_api.quota_destroy.return_value = Res
|
||||
data = {"quota_set": [Res.resource]}
|
||||
try:
|
||||
self.app.delete_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant, 'X_ROLE': 'admin'},
|
||||
params=data)
|
||||
except webtest.app.AppError as invalid_quota_exception:
|
||||
self.assertIn('The resource could not be found',
|
||||
invalid_quota_exception.message)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "404 *",
|
||||
self.app.delete_json, fake_url,
|
||||
headers=ADMIN_HEADERS, params=data)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
def test_quota_sync_bad_action(self):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s/syncing'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
try:
|
||||
self.app.put_json(
|
||||
fake_url,
|
||||
headers={'X-Tenant-Id': fake_tenant,
|
||||
'X_ROLE': 'admin'})
|
||||
except webtest.app.AppError as bad_method_exception:
|
||||
self.assertIn('Invalid action, only sync is allowed',
|
||||
bad_method_exception.message)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "404 *",
|
||||
self.app.delete_json, fake_url,
|
||||
headers=ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_get_all_another_tenant_nonadmin(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
FAKE_HEADERS = {'X_TENANT_ID': fake_tenant,
|
||||
'X_USER_ID': 'nonadmin'}
|
||||
% (TARGET_FAKE_TENANT, FAKE_TENANT)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "403 *",
|
||||
self.app.get, fake_url,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_get_all_another_tenant_with_admin(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
Res = Result('tenant_1', 'ram', 100)
|
||||
mock_db_api.quota_get_all_by_project.return_value = \
|
||||
{"project_id": Res.project_id,
|
||||
Res.resource: Res.hard_limit}
|
||||
response = self.app.get(
|
||||
fake_url,
|
||||
headers={'X_TENANT_ID': fake_tenant, 'X_ROLE': 'admin',
|
||||
'X_USER_ID': 'nonadmin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual({'quota_set': {'project_id': 'tenant_1', 'ram': 100}},
|
||||
eval(response.text))
|
||||
|
@ -357,76 +287,63 @@ class TestQuotaManager(testroot.KBApiTest):
|
|||
@mock.patch.object(rpc_client, 'EngineClient', new=mock.Mock())
|
||||
@mock.patch.object(quota_manager, 'db_api')
|
||||
def test_get_usages_another_tenant_no_admin(self, mock_db_api):
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s/detail'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
FAKE_HEADERS = {'X_TENANT_ID': fake_tenant,
|
||||
'X_USER_ID': 'nonadmin'}
|
||||
% (TARGET_FAKE_TENANT, FAKE_TENANT)
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "403 *",
|
||||
self.app.get, fake_url,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient')
|
||||
def test_get_usages_another_tenant_admin(self, mock_rpc_client):
|
||||
expected_usage = {"ram": 10}
|
||||
fake_tenant = uuidutils.generate_uuid()
|
||||
target_fake_tenant = uuidutils.generate_uuid()
|
||||
fake_url = '/v1.0/%s/os-quota-sets/%s/detail'\
|
||||
% (fake_tenant, target_fake_tenant)
|
||||
% (FAKE_TENANT, TARGET_FAKE_TENANT)
|
||||
mock_rpc_client().get_total_usage_for_tenant.return_value = \
|
||||
expected_usage
|
||||
response = self.app.get(
|
||||
fake_url,
|
||||
headers={'X_TENANT_ID': fake_tenant, 'X_ROLE': 'admin',
|
||||
'X_USER_ID': 'admin'})
|
||||
headers=ADMIN_HEADERS)
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertEqual(eval(response.body), {"quota_set": expected_usage})
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient')
|
||||
def test_get_invalid_curl_req_nonadmin(self, mock_rpc_client):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-sets/defaults'
|
||||
FAKE_HEADERS = {'X_ROLE': 'nonadmin'}
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.get, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient')
|
||||
def test_get_invalid_curl_req_admin(self, mock_rpc_client):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-sets/defaults'
|
||||
FAKE_HEADERS = {'X_ROLE': 'admin'}
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.get, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient')
|
||||
def test_put_invalid_curl_req_nonadmin(self, mock_rpc_client):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-sets/dummy2/sync'
|
||||
FAKE_HEADERS = {'X_ROLE': 'nonadmin'}
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.put, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient')
|
||||
def test_put_invalid_curl_req_admin(self, mock_rpc_client):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-sets/dummy2'
|
||||
FAKE_HEADERS = {'X_ROLE': 'admin'}
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.put, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient')
|
||||
def test_delete_invalid_curl_req_nonadmin(self, mock_rpc_client):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-sets/dummy2'
|
||||
FAKE_HEADERS = {'X_ROLE': 'nonadmin'}
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.delete, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
||||
@mock.patch.object(rpc_client, 'EngineClient')
|
||||
def test_delete_invalid_curl_req_admin(self, mock_rpc_client):
|
||||
FAKE_URL = '/v1.0/dummy/os-quota-sets/dummy2'
|
||||
FAKE_HEADERS = {'X_ROLE': 'admin'}
|
||||
self.assertRaisesRegexp(webtest.app.AppError, "400 *",
|
||||
self.app.delete, FAKE_URL,
|
||||
headers=FAKE_HEADERS)
|
||||
headers=NON_ADMIN_HEADERS)
|
||||
|
|
|
@ -188,6 +188,14 @@ class TestKeystoneAuth(KBApiTest):
|
|||
|
||||
self.app = self._make_app()
|
||||
|
||||
def test_auth_not_enforced_for_root(self):
|
||||
response = self.app.get('/')
|
||||
self.assertEqual(response.status_int, 200)
|
||||
|
||||
def test_auth_not_enforced_for_v1(self):
|
||||
response = self.app.get('/v1.0')
|
||||
self.assertEqual(response.status_int, 200)
|
||||
|
||||
def test_auth_enforced(self):
|
||||
response = self.app.get('/', expect_errors=True)
|
||||
response = self.app.get('/v1.0/', expect_errors=True)
|
||||
self.assertEqual(response.status_int, 401)
|
||||
|
|
Loading…
Reference in New Issue