summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-01-24 19:32:49 +0000
committerGerrit Code Review <review@openstack.org>2012-01-24 19:32:49 +0000
commit8dfd968e83cbcdc0796caa44289144d38a6a5ce8 (patch)
treee0e2e571a9aae49fc71736ad034d8fb6ed31b0b0 /nova/api
parentc88771d8202f9c1c3f7a7260dea200d902b3c3aa (diff)
parent9cb5f547dc6f3242edf393928dbc14b7cbfbbdd4 (diff)
downloadnova-8dfd968e83cbcdc0796caa44289144d38a6a5ce8.tar.gz
nova-8dfd968e83cbcdc0796caa44289144d38a6a5ce8.tar.xz
nova-8dfd968e83cbcdc0796caa44289144d38a6a5ce8.zip
Merge "Remove admin_only ext attr in favor of authz"
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/mapper.py3
-rw-r--r--nova/api/openstack/compute/__init__.py3
-rw-r--r--nova/api/openstack/compute/contrib/accounts.py17
-rw-r--r--nova/api/openstack/compute/contrib/admin_actions.py12
-rw-r--r--nova/api/openstack/compute/contrib/cloudpipe.py6
-rw-r--r--nova/api/openstack/compute/contrib/console_output.py4
-rw-r--r--nova/api/openstack/compute/contrib/consoles.py2
-rw-r--r--nova/api/openstack/compute/contrib/createserverext.py7
-rw-r--r--nova/api/openstack/compute/contrib/deferred_delete.py5
-rw-r--r--nova/api/openstack/compute/contrib/disk_config.py57
-rw-r--r--nova/api/openstack/compute/contrib/extended_status.py48
-rw-r--r--nova/api/openstack/compute/contrib/flavorextraspecs.py12
-rw-r--r--nova/api/openstack/compute/contrib/floating_ip_dns.py8
-rw-r--r--nova/api/openstack/compute/contrib/floating_ip_pools.py2
-rw-r--r--nova/api/openstack/compute/contrib/floating_ips.py7
-rw-r--r--nova/api/openstack/compute/contrib/hosts.py5
-rw-r--r--nova/api/openstack/compute/contrib/keypairs.py6
-rw-r--r--nova/api/openstack/compute/contrib/multinic.py7
-rw-r--r--nova/api/openstack/compute/contrib/networks.py6
-rw-r--r--nova/api/openstack/compute/contrib/quotas.py6
-rw-r--r--nova/api/openstack/compute/contrib/rescue.py3
-rw-r--r--nova/api/openstack/compute/contrib/security_groups.py9
-rw-r--r--nova/api/openstack/compute/contrib/server_action_list.py3
-rw-r--r--nova/api/openstack/compute/contrib/server_diagnostics.py3
-rw-r--r--nova/api/openstack/compute/contrib/simple_tenant_usage.py4
-rw-r--r--nova/api/openstack/compute/contrib/users.py16
-rw-r--r--nova/api/openstack/compute/contrib/virtual_interfaces.py2
-rw-r--r--nova/api/openstack/compute/contrib/virtual_storage_arrays.py15
-rw-r--r--nova/api/openstack/compute/contrib/volumes.py15
-rw-r--r--nova/api/openstack/compute/contrib/volumetypes.py16
-rw-r--r--nova/api/openstack/compute/contrib/zones.py15
-rw-r--r--nova/api/openstack/compute/servers.py2
-rw-r--r--nova/api/openstack/extensions.py33
33 files changed, 246 insertions, 113 deletions
diff --git a/nova/api/mapper.py b/nova/api/mapper.py
index cd26e06ee..aaa59f97f 100644
--- a/nova/api/mapper.py
+++ b/nova/api/mapper.py
@@ -32,9 +32,6 @@ from nova import wsgi as base_wsgi
LOG = logging.getLogger('nova.api.openstack.compute')
FLAGS = flags.FLAGS
-flags.DEFINE_bool('allow_admin_api',
- False,
- 'When True, this API service will accept admin operations.')
flags.DEFINE_bool('allow_instance_snapshots',
True,
'When True, this API service will permit instance snapshot operations.')
diff --git a/nova/api/openstack/compute/__init__.py b/nova/api/openstack/compute/__init__.py
index 9e0509e71..f074ac941 100644
--- a/nova/api/openstack/compute/__init__.py
+++ b/nova/api/openstack/compute/__init__.py
@@ -42,9 +42,6 @@ from nova import wsgi as base_wsgi
LOG = logging.getLogger('nova.api.openstack.compute')
FLAGS = flags.FLAGS
-flags.DEFINE_bool('allow_admin_api',
- False,
- 'When True, this API service will accept admin operations.')
flags.DEFINE_bool('allow_instance_snapshots',
True,
'When True, this API service will permit instance snapshot operations.')
diff --git a/nova/api/openstack/compute/contrib/accounts.py b/nova/api/openstack/compute/contrib/accounts.py
index 9253c037d..939912942 100644
--- a/nova/api/openstack/compute/contrib/accounts.py
+++ b/nova/api/openstack/compute/contrib/accounts.py
@@ -26,6 +26,7 @@ from nova import log as logging
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.api.openstack.compute.contrib.accounts')
+authorize = extensions.extension_authorizer('compute', 'accounts')
class AccountTemplate(xmlutil.TemplateBuilder):
@@ -51,23 +52,18 @@ class Controller(object):
def __init__(self):
self.manager = manager.AuthManager()
- def _check_admin(self, context):
- """We cannot depend on the db layer to check for admin access
- for the auth manager, so we do it here"""
- if not context.is_admin:
- raise exception.AdminRequired()
-
def index(self, req):
raise webob.exc.HTTPNotImplemented()
@wsgi.serializers(xml=AccountTemplate)
def show(self, req, id):
"""Return data about the given account id"""
+ authorize(req.environ['nova.context'])
account = self.manager.get_project(id)
return dict(account=_translate_keys(account))
def delete(self, req, id):
- self._check_admin(req.environ['nova.context'])
+ authorize(req.environ['nova.context'])
self.manager.delete_project(id)
return {}
@@ -79,7 +75,7 @@ class Controller(object):
@wsgi.serializers(xml=AccountTemplate)
def update(self, req, id, body):
"""This is really create or update."""
- self._check_admin(req.environ['nova.context'])
+ authorize(req.environ['nova.context'])
description = body['account'].get('description')
manager = body['account'].get('manager')
try:
@@ -97,11 +93,8 @@ class Accounts(extensions.ExtensionDescriptor):
alias = "os-accounts"
namespace = "http://docs.openstack.org/compute/ext/accounts/api/v1.1"
updated = "2011-12-23T00:00:00+00:00"
- admin_only = True
def get_resources(self):
#TODO(bcwaldon): This should be prefixed with 'os-'
- res = extensions.ResourceExtension('accounts',
- Controller())
-
+ res = extensions.ResourceExtension('accounts', Controller())
return [res]
diff --git a/nova/api/openstack/compute/contrib/admin_actions.py b/nova/api/openstack/compute/contrib/admin_actions.py
index b44f16a1e..cbd54117d 100644
--- a/nova/api/openstack/compute/contrib/admin_actions.py
+++ b/nova/api/openstack/compute/contrib/admin_actions.py
@@ -30,6 +30,7 @@ from nova.scheduler import api as scheduler_api
FLAGS = flags.FLAGS
LOG = logging.getLogger("nova.api.openstack.compute.contrib.admin_actions")
+authorize = extensions.extension_authorizer('compute', 'admin_actions')
class AdminActionsController(wsgi.Controller):
@@ -45,6 +46,7 @@ class AdminActionsController(wsgi.Controller):
def _pause(self, req, id, body):
"""Permit Admins to pause the server"""
ctxt = req.environ['nova.context']
+ authorize(ctxt)
try:
server = self.compute_api.get(ctxt, id)
self.compute_api.pause(ctxt, server)
@@ -63,6 +65,7 @@ class AdminActionsController(wsgi.Controller):
def _unpause(self, req, id, body):
"""Permit Admins to unpause the server"""
ctxt = req.environ['nova.context']
+ authorize(ctxt)
try:
server = self.compute_api.get(ctxt, id)
self.compute_api.unpause(ctxt, server)
@@ -81,6 +84,7 @@ class AdminActionsController(wsgi.Controller):
def _suspend(self, req, id, body):
"""Permit admins to suspend the server"""
context = req.environ['nova.context']
+ authorize(context)
try:
server = self.compute_api.get(context, id)
self.compute_api.suspend(context, server)
@@ -99,6 +103,7 @@ class AdminActionsController(wsgi.Controller):
def _resume(self, req, id, body):
"""Permit admins to resume the server from suspend"""
context = req.environ['nova.context']
+ authorize(context)
try:
server = self.compute_api.get(context, id)
self.compute_api.resume(context, server)
@@ -117,6 +122,7 @@ class AdminActionsController(wsgi.Controller):
def _migrate(self, req, id, body):
"""Permit admins to migrate a server to a new host"""
context = req.environ['nova.context']
+ authorize(context)
try:
instance = self.compute_api.get(context, id)
self.compute_api.resize(req.environ['nova.context'], instance)
@@ -134,6 +140,7 @@ class AdminActionsController(wsgi.Controller):
def _reset_network(self, req, id, body):
"""Permit admins to reset networking on an server"""
context = req.environ['nova.context']
+ authorize(context)
try:
instance = self.compute_api.get(context, id)
self.compute_api.reset_network(context, instance)
@@ -149,6 +156,7 @@ class AdminActionsController(wsgi.Controller):
def _inject_network_info(self, req, id, body):
"""Permit admins to inject network info into a server"""
context = req.environ['nova.context']
+ authorize(context)
try:
instance = self.compute_api.get(context, id)
self.compute_api.inject_network_info(context, instance)
@@ -166,6 +174,7 @@ class AdminActionsController(wsgi.Controller):
def _lock(self, req, id, body):
"""Permit admins to lock a server"""
context = req.environ['nova.context']
+ authorize(context)
try:
instance = self.compute_api.get(context, id)
self.compute_api.lock(context, instance)
@@ -183,6 +192,7 @@ class AdminActionsController(wsgi.Controller):
def _unlock(self, req, id, body):
"""Permit admins to lock a server"""
context = req.environ['nova.context']
+ authorize(context)
try:
instance = self.compute_api.get(context, id)
self.compute_api.unlock(context, instance)
@@ -207,6 +217,7 @@ class AdminActionsController(wsgi.Controller):
"""
context = req.environ["nova.context"]
+ authorize(context)
try:
entity = body["createBackup"]
@@ -273,7 +284,6 @@ class Admin_actions(extensions.ExtensionDescriptor):
alias = "os-admin-actions"
namespace = "http://docs.openstack.org/compute/ext/admin-actions/api/v1.1"
updated = "2011-09-20T00:00:00+00:00"
- admin_only = True
def get_controller_extensions(self):
controller = AdminActionsController()
diff --git a/nova/api/openstack/compute/contrib/cloudpipe.py b/nova/api/openstack/compute/contrib/cloudpipe.py
index 17bfa810b..1cf47a2a9 100644
--- a/nova/api/openstack/compute/contrib/cloudpipe.py
+++ b/nova/api/openstack/compute/contrib/cloudpipe.py
@@ -32,6 +32,7 @@ from nova import utils
FLAGS = flags.FLAGS
LOG = logging.getLogger("nova.api.openstack.compute.contrib.cloudpipe")
+authorize = extensions.extension_authorizer('compute', 'cloudpipe')
class CloudpipeTemplate(xmlutil.TemplateBuilder):
@@ -120,6 +121,7 @@ class CloudpipeController(object):
"""
ctxt = req.environ['nova.context']
+ authorize(ctxt)
params = body.get('cloudpipe', {})
project_id = params.get('project_id', ctxt.project_id)
instance = self._get_cloudpipe_for_project(ctxt, project_id)
@@ -137,8 +139,9 @@ class CloudpipeController(object):
@wsgi.serializers(xml=CloudpipesTemplate)
def index(self, req):
- """Show admins the list of running cloudpipe instances."""
+ """List running cloudpipe instances."""
context = req.environ['nova.context']
+ authorize(context)
vpns = []
# TODO(todd): could use compute_api.get_all with admin context?
for project in self.auth_manager.get_projects():
@@ -162,7 +165,6 @@ class Cloudpipe(extensions.ExtensionDescriptor):
alias = "os-cloudpipe"
namespace = "http://docs.openstack.org/compute/ext/cloudpipe/api/v1.1"
updated = "2011-12-16T00:00:00+00:00"
- admin_only = True
def get_resources(self):
resources = []
diff --git a/nova/api/openstack/compute/contrib/console_output.py b/nova/api/openstack/compute/contrib/console_output.py
index ac578676e..04f975d5b 100644
--- a/nova/api/openstack/compute/contrib/console_output.py
+++ b/nova/api/openstack/compute/contrib/console_output.py
@@ -26,6 +26,7 @@ from nova.api.openstack import wsgi
LOG = logging.getLogger('nova.api.openstack.compute.contrib.console_output')
+authorize = extensions.extension_authorizer('compute', 'console_output')
class ConsoleOutputController(wsgi.Controller):
@@ -37,6 +38,7 @@ class ConsoleOutputController(wsgi.Controller):
def get_console_output(self, req, id, body):
"""Get text console output."""
context = req.environ['nova.context']
+ authorize(context)
try:
instance = self.compute_api.routing_get(context, id)
@@ -54,8 +56,6 @@ class ConsoleOutputController(wsgi.Controller):
length)
except exception.ApiError, e:
raise webob.exc.HTTPBadRequest(explanation=e.message)
- except exception.NotAuthorized, e:
- raise webob.exc.HTTPUnauthorized()
return {'output': output}
diff --git a/nova/api/openstack/compute/contrib/consoles.py b/nova/api/openstack/compute/contrib/consoles.py
index 46e3559ff..c3509e7a8 100644
--- a/nova/api/openstack/compute/contrib/consoles.py
+++ b/nova/api/openstack/compute/contrib/consoles.py
@@ -24,6 +24,7 @@ from nova.api.openstack import wsgi
LOG = logging.getLogger('nova.api.openstack.compute.contrib.console')
+authorize = extensions.extension_authorizer('compute', 'consoles')
class ConsolesController(wsgi.Controller):
@@ -35,6 +36,7 @@ class ConsolesController(wsgi.Controller):
def get_vnc_console(self, req, id, body):
"""Get text console output."""
context = req.environ['nova.context']
+ authorize(context)
console_type = body['os-getVNCConsole'].get('type')
diff --git a/nova/api/openstack/compute/contrib/createserverext.py b/nova/api/openstack/compute/contrib/createserverext.py
index 05b0c7d9c..de4ba8dd0 100644
--- a/nova/api/openstack/compute/contrib/createserverext.py
+++ b/nova/api/openstack/compute/contrib/createserverext.py
@@ -19,13 +19,18 @@ from nova.api.openstack.compute import servers
from nova.api.openstack.compute import views
+authorize = extensions.soft_extension_authorizer('compute', 'createserverext')
+
+
class ViewBuilder(views.servers.ViewBuilder):
"""Adds security group output when viewing server details."""
def show(self, request, instance):
"""Detailed view of a single instance."""
server = super(ViewBuilder, self).show(request, instance)
- server["server"]["security_groups"] = self._get_groups(instance)
+ context = request.environ['nova.context']
+ if authorize(context):
+ server["server"]["security_groups"] = self._get_groups(instance)
return server
def _get_groups(self, instance):
diff --git a/nova/api/openstack/compute/contrib/deferred_delete.py b/nova/api/openstack/compute/contrib/deferred_delete.py
index c0164eead..10f776558 100644
--- a/nova/api/openstack/compute/contrib/deferred_delete.py
+++ b/nova/api/openstack/compute/contrib/deferred_delete.py
@@ -26,6 +26,7 @@ from nova import log as logging
LOG = logging.getLogger("nova.api.openstack.compute.contrib.deferred-delete")
+authorize = extensions.extension_authorizer('compute', 'deferred_delete')
class DeferredDeleteController(wsgi.Controller):
@@ -36,8 +37,8 @@ class DeferredDeleteController(wsgi.Controller):
@wsgi.action('restore')
def _restore(self, req, id, body):
"""Restore a previously deleted instance."""
-
context = req.environ["nova.context"]
+ authorize(context)
instance = self.compute_api.get(context, id)
try:
self.compute_api.restore(context, instance)
@@ -49,8 +50,8 @@ class DeferredDeleteController(wsgi.Controller):
@wsgi.action('forceDelete')
def _force_delete(self, req, id, body):
"""Force delete of instance before deferred cleanup."""
-
context = req.environ["nova.context"]
+ authorize(context)
instance = self.compute_api.get(context, id)
try:
self.compute_api.force_delete(context, instance)
diff --git a/nova/api/openstack/compute/contrib/disk_config.py b/nova/api/openstack/compute/contrib/disk_config.py
index cf78b847e..46c09ffa8 100644
--- a/nova/api/openstack/compute/contrib/disk_config.py
+++ b/nova/api/openstack/compute/contrib/disk_config.py
@@ -28,6 +28,7 @@ ALIAS = 'OS-DCF'
XMLNS_DCF = "http://docs.openstack.org/compute/ext/disk_config/api/v1.1"
API_DISK_CONFIG = "%s:diskConfig" % ALIAS
INTERNAL_DISK_CONFIG = "auto_disk_config"
+authorize = extensions.soft_extension_authorizer('compute', 'disk_config')
def disk_config_to_api(value):
@@ -70,16 +71,16 @@ class ImageDiskConfigController(wsgi.Controller):
@wsgi.extends
def show(self, req, resp_obj, id):
- if 'image' in resp_obj.obj:
- context = req.environ['nova.context']
+ context = req.environ['nova.context']
+ if 'image' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ImageDiskConfigTemplate())
image = resp_obj.obj['image']
self._add_disk_config(context, [image])
@wsgi.extends
def detail(self, req, resp_obj):
- if 'images' in resp_obj.obj:
- context = req.environ['nova.context']
+ context = req.environ['nova.context']
+ if 'images' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ImagesDiskConfigTemplate())
images = resp_obj.obj['images']
self._add_disk_config(context, images)
@@ -102,13 +103,14 @@ class ServersDiskConfigTemplate(xmlutil.TemplateBuilder):
class ServerDiskConfigController(wsgi.Controller):
def _add_disk_config(self, context, servers):
- # Filter out any servers that already have the key set (most likely
- # from a remote zone)
+ # Filter out any servers that already have the key set
+ # (most likely from a remote zone)
servers = [s for s in servers if API_DISK_CONFIG not in s]
# Get DB information for servers
uuids = [server['id'] for server in servers]
- db_servers = db.instance_get_all_by_filters(context, {'uuid': uuids})
+ db_servers = db.instance_get_all_by_filters(context,
+ {'uuid': uuids})
db_servers_by_uuid = dict((s['uuid'], s) for s in db_servers)
for server in servers:
@@ -117,21 +119,22 @@ class ServerDiskConfigController(wsgi.Controller):
value = db_server[INTERNAL_DISK_CONFIG]
server[API_DISK_CONFIG] = disk_config_to_api(value)
- def _show(self, req, resp_obj):
+ def _show(self, context, resp_obj):
if 'server' in resp_obj.obj:
- context = req.environ['nova.context']
resp_obj.attach(xml=ServerDiskConfigTemplate())
server = resp_obj.obj['server']
self._add_disk_config(context, [server])
@wsgi.extends
def show(self, req, resp_obj, id):
- self._show(req, resp_obj)
+ context = req.environ['nova.context']
+ if authorize(context):
+ self._show(context, resp_obj)
@wsgi.extends
def detail(self, req, resp_obj):
- if 'servers' in resp_obj.obj:
- context = req.environ['nova.context']
+ context = req.environ['nova.context']
+ if 'servers' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ServersDiskConfigTemplate())
servers = resp_obj.obj['servers']
self._add_disk_config(context, servers)
@@ -144,26 +147,34 @@ class ServerDiskConfigController(wsgi.Controller):
@wsgi.extends
def create(self, req, body):
- self._set_disk_config(body['server'])
- resp_obj = (yield)
- self._show(req, resp_obj)
+ context = req.environ['nova.context']
+ if authorize(context):
+ self._set_disk_config(body['server'])
+ resp_obj = (yield)
+ self._show(context, resp_obj)
@wsgi.extends
def update(self, req, id, body):
- self._set_disk_config(body['server'])
- resp_obj = (yield)
- self._show(req, resp_obj)
+ context = req.environ['nova.context']
+ if authorize(context):
+ self._set_disk_config(body['server'])
+ resp_obj = (yield)
+ self._show(context, resp_obj)
@wsgi.extends(action='rebuild')
def _action_rebuild(self, req, id, body):
- self._set_disk_config(body['rebuild'])
- resp_obj = (yield)
- self._show(req, resp_obj)
+ context = req.environ['nova.context']
+ if authorize(context):
+ self._set_disk_config(body['rebuild'])
+ resp_obj = (yield)
+ self._show(context, resp_obj)
@wsgi.extends(action='resize')
def _action_resize(self, req, id, body):
- self._set_disk_config(body['resize'])
- yield
+ context = req.environ['nova.context']
+ if authorize(context):
+ self._set_disk_config(body['resize'])
+ yield
class Disk_config(extensions.ExtensionDescriptor):
diff --git a/nova/api/openstack/compute/contrib/extended_status.py b/nova/api/openstack/compute/contrib/extended_status.py
index 7479d6f00..4ab7ca756 100644
--- a/nova/api/openstack/compute/contrib/extended_status.py
+++ b/nova/api/openstack/compute/contrib/extended_status.py
@@ -27,6 +27,7 @@ from nova import log as logging
FLAGS = flags.FLAGS
LOG = logging.getLogger("nova.api.openstack.compute.contrib.extendedstatus")
+authorize = extensions.soft_extension_authorizer('compute', 'extended_status')
class ExtendedStatusController(wsgi.Controller):
@@ -48,34 +49,34 @@ class ExtendedStatusController(wsgi.Controller):
@wsgi.extends
def show(self, req, resp_obj, id):
context = req.environ['nova.context']
+ if authorize(context):
+ # Attach our slave template to the response object
+ resp_obj.attach(xml=ExtendedStatusTemplate())
- # Attach our slave template to the response object
- resp_obj.attach(xml=ExtendedStatusTemplate())
-
- try:
- self._get_and_extend_one(context, id, resp_obj.obj['server'])
- except exception.NotFound:
- explanation = _("Server not found.")
- raise exc.HTTPNotFound(explanation=explanation)
+ try:
+ self._get_and_extend_one(context, id, resp_obj.obj['server'])
+ except exception.NotFound:
+ explanation = _("Server not found.")
+ raise exc.HTTPNotFound(explanation=explanation)
@wsgi.extends
def detail(self, req, resp_obj):
context = req.environ['nova.context']
-
- # Attach our slave template to the response object
- resp_obj.attach(xml=ExtendedStatusesTemplate())
-
- for server in list(resp_obj.obj['servers']):
- try:
- self._get_and_extend_one(context, server['id'], server)
- except exception.NotFound:
- # NOTE(dtroyer): A NotFound exception at this point
- # happens because a delete was in progress and the
- # server that was present in the original call to
- # compute.api.get_all() is no longer present.
- # Delete it from the response and move on.
- resp_obj.obj['servers'].remove(server)
- continue
+ if authorize(context):
+ # Attach our slave template to the response object
+ resp_obj.attach(xml=ExtendedStatusesTemplate())
+
+ for server in list(resp_obj.obj['servers']):
+ try:
+ self._get_and_extend_one(context, server['id'], server)
+ except exception.NotFound:
+ # NOTE(dtroyer): A NotFound exception at this point
+ # happens because a delete was in progress and the
+ # server that was present in the original call to
+ # compute.api.get_all() is no longer present.
+ # Delete it from the response and move on.
+ resp_obj.obj['servers'].remove(server)
+ continue
class Extended_status(extensions.ExtensionDescriptor):
@@ -86,7 +87,6 @@ class Extended_status(extensions.ExtensionDescriptor):
namespace = "http://docs.openstack.org/compute/ext/" \
"extended_status/api/v1.1"
updated = "2011-11-03T00:00:00+00:00"
- admin_only = True
def get_controller_extensions(self):
controller = ExtendedStatusController()
diff --git a/nova/api/openstack/compute/contrib/flavorextraspecs.py b/nova/api/openstack/compute/contrib/flavorextraspecs.py
index eafea5d1f..faf023659 100644
--- a/nova/api/openstack/compute/contrib/flavorextraspecs.py
+++ b/nova/api/openstack/compute/contrib/flavorextraspecs.py
@@ -26,6 +26,9 @@ from nova import db
from nova import exception
+authorize = extensions.extension_authorizer('compute', 'flavorextraspecs')
+
+
class ExtraSpecsTemplate(xmlutil.TemplateBuilder):
def construct(self):
return xmlutil.MasterTemplate(xmlutil.make_flat_dict('extra_specs'), 1)
@@ -50,12 +53,14 @@ class FlavorExtraSpecsController(object):
def index(self, req, flavor_id):
""" Returns the list of extra specs for a givenflavor """
context = req.environ['nova.context']
+ authorize(context)
return self._get_extra_specs(context, flavor_id)
@wsgi.serializers(xml=ExtraSpecsTemplate)
def create(self, req, flavor_id, body):
- self._check_body(body)
context = req.environ['nova.context']
+ authorize(context)
+ self._check_body(body)
specs = body.get('extra_specs')
try:
db.instance_type_extra_specs_update_or_create(context,
@@ -67,8 +72,9 @@ class FlavorExtraSpecsController(object):
@wsgi.serializers(xml=ExtraSpecsTemplate)
def update(self, req, flavor_id, id, body):
- self._check_body(body)
context = req.environ['nova.context']
+ authorize(context)
+ self._check_body(body)
if not id in body:
expl = _('Request body and URI mismatch')
raise exc.HTTPBadRequest(explanation=expl)
@@ -88,6 +94,7 @@ class FlavorExtraSpecsController(object):
def show(self, req, flavor_id, id):
""" Return a single extra spec item """
context = req.environ['nova.context']
+ authorize(context)
specs = self._get_extra_specs(context, flavor_id)
if id in specs['extra_specs']:
return {id: specs['extra_specs'][id]}
@@ -97,6 +104,7 @@ class FlavorExtraSpecsController(object):
def delete(self, req, flavor_id, id):
""" Deletes an existing extra spec """
context = req.environ['nova.context']
+ authorize(context)
db.instance_type_extra_specs_delete(context, flavor_id, id)
def _handle_quota_error(self, error):
diff --git a/nova/api/openstack/compute/contrib/floating_ip_dns.py b/nova/api/openstack/compute/contrib/floating_ip_dns.py
index a0ac9241f..dbdd0c3a9 100644
--- a/nova/api/openstack/compute/contrib/floating_ip_dns.py
+++ b/nova/api/openstack/compute/contrib/floating_ip_dns.py
@@ -27,6 +27,7 @@ from nova import network
LOG = logging.getLogger('nova.api.openstack.compute.contrib.floating_ip_dns')
+authorize = extensions.extension_authorizer('compute', 'floating_ip_dns')
def make_dns_entry(elem):
@@ -138,6 +139,7 @@ class FloatingIPDNSDomainController(object):
def index(self, req):
"""Return a list of available DNS domains."""
context = req.environ['nova.context']
+ authorize(context)
domains = self.network_api.get_dns_domains(context)
domainlist = [_create_domain_entry(domain['domain'],
domain.get('scope'),
@@ -151,6 +153,7 @@ class FloatingIPDNSDomainController(object):
def update(self, req, id, body):
"""Add or modify domain entry"""
context = req.environ['nova.context']
+ authorize(context)
fqdomain = _unquote_domain(id)
try:
entry = body['domain_entry']
@@ -185,6 +188,7 @@ class FloatingIPDNSDomainController(object):
def delete(self, req, id):
"""Delete the domain identified by id. """
context = req.environ['nova.context']
+ authorize(context)
params = req.str_GET
domain = _unquote_domain(id)
@@ -210,6 +214,7 @@ class FloatingIPDNSEntryController(object):
def show(self, req, domain_id, id):
"""Return the DNS entry that corresponds to domain_id and id."""
context = req.environ['nova.context']
+ authorize(context)
domain = _unquote_domain(domain_id)
name = id
@@ -222,6 +227,7 @@ class FloatingIPDNSEntryController(object):
def index(self, req, domain_id):
"""Return a list of dns entries for the specified domain and ip."""
context = req.environ['nova.context']
+ authorize(context)
params = req.GET
floating_ip = params.get('ip')
domain = _unquote_domain(domain_id)
@@ -241,6 +247,7 @@ class FloatingIPDNSEntryController(object):
def update(self, req, domain_id, id, body):
"""Add or modify dns entry"""
context = req.environ['nova.context']
+ authorize(context)
domain = _unquote_domain(domain_id)
name = id
try:
@@ -268,6 +275,7 @@ class FloatingIPDNSEntryController(object):
def delete(self, req, domain_id, id):
"""Delete the entry identified by req and id. """
context = req.environ['nova.context']
+ authorize(context)
domain = _unquote_domain(domain_id)
name = id
diff --git a/nova/api/openstack/compute/contrib/floating_ip_pools.py b/nova/api/openstack/compute/contrib/floating_ip_pools.py
index 0bf2362af..574ef26b0 100644
--- a/nova/api/openstack/compute/contrib/floating_ip_pools.py
+++ b/nova/api/openstack/compute/contrib/floating_ip_pools.py
@@ -22,6 +22,7 @@ from nova import network
LOG = logging.getLogger('nova.api.openstack.compute.contrib.floating_ip_pools')
+authorize = extensions.extension_authorizer('compute', 'floating_ip_pools')
def _translate_floating_ip_view(pool):
@@ -69,6 +70,7 @@ class FloatingIPPoolsController(object):
def index(self, req):
"""Return a list of pools."""
context = req.environ['nova.context']
+ authorize(context)
pools = self.network_api.get_floating_ip_pools(context)
return _translate_floating_ip_pools_view(pools)
diff --git a/nova/api/openstack/compute/contrib/floating_ips.py b/nova/api/openstack/compute/contrib/floating_ips.py
index 3cfbc0604..afbdcf83a 100644
--- a/nova/api/openstack/compute/contrib/floating_ips.py
+++ b/nova/api/openstack/compute/contrib/floating_ips.py
@@ -30,6 +30,7 @@ from nova import rpc
LOG = logging.getLogger('nova.api.openstack.compute.contrib.floating_ips')
+authorize = extensions.extension_authorizer('compute', 'floating_ips')
def make_float_ip(elem):
@@ -116,6 +117,7 @@ class FloatingIPController(object):
def show(self, req, id):
"""Return data about the given floating ip."""
context = req.environ['nova.context']
+ authorize(context)
try:
floating_ip = self.network_api.get_floating_ip(context, id)
@@ -130,6 +132,7 @@ class FloatingIPController(object):
def index(self, req):
"""Return a list of floating ips allocated to a project."""
context = req.environ['nova.context']
+ authorize(context)
floating_ips = self.network_api.get_floating_ips_by_project(context)
@@ -141,6 +144,7 @@ class FloatingIPController(object):
@wsgi.serializers(xml=FloatingIPTemplate)
def create(self, req, body=None):
context = req.environ['nova.context']
+ authorize(context)
pool = None
if body and 'pool' in body:
@@ -163,6 +167,7 @@ class FloatingIPController(object):
def delete(self, req, id):
context = req.environ['nova.context']
+ authorize(context)
floating_ip = self.network_api.get_floating_ip(context, id)
if floating_ip.get('fixed_ip_id'):
@@ -188,6 +193,7 @@ class FloatingIPActionController(wsgi.Controller):
def _add_floating_ip(self, req, id, body):
"""Associate floating_ip to an instance."""
context = req.environ['nova.context']
+ authorize(context)
try:
address = body['addFloatingIp']['address']
@@ -213,6 +219,7 @@ class FloatingIPActionController(wsgi.Controller):
def _remove_floating_ip(self, req, id, body):
"""Dissociate floating_ip from an instance."""
context = req.environ['nova.context']
+ authorize(context)
try:
address = body['removeFloatingIp']['address']
diff --git a/nova/api/openstack/compute/contrib/hosts.py b/nova/api/openstack/compute/contrib/hosts.py
index 66dd64def..6ee89859b 100644
--- a/nova/api/openstack/compute/contrib/hosts.py
+++ b/nova/api/openstack/compute/contrib/hosts.py
@@ -31,6 +31,7 @@ from nova.scheduler import api as scheduler_api
LOG = logging.getLogger("nova.api.openstack.compute.contrib.hosts")
FLAGS = flags.FLAGS
+authorize = extensions.extension_authorizer('compute', 'hosts')
class HostIndexTemplate(xmlutil.TemplateBuilder):
@@ -112,12 +113,14 @@ class HostController(object):
@wsgi.serializers(xml=HostIndexTemplate)
def index(self, req):
+ authorize(req.environ['nova.context'])
return {'hosts': _list_hosts(req)}
@wsgi.serializers(xml=HostUpdateTemplate)
@wsgi.deserializers(xml=HostDeserializer)
@check_host
def update(self, req, id, body):
+ authorize(req.environ['nova.context'])
for raw_key, raw_val in body.iteritems():
key = raw_key.lower().strip()
val = raw_val.lower().strip()
@@ -149,6 +152,7 @@ class HostController(object):
def _host_power_action(self, req, host, action):
"""Reboots, shuts down or powers up the host."""
context = req.environ['nova.context']
+ authorize(context)
try:
result = self.compute_api.host_power_action(context, host=host,
action=action)
@@ -176,7 +180,6 @@ class Hosts(extensions.ExtensionDescriptor):
alias = "os-hosts"
namespace = "http://docs.openstack.org/compute/ext/hosts/api/v1.1"
updated = "2011-06-29T00:00:00+00:00"
- admin_only = True
def get_resources(self):
resources = [extensions.ResourceExtension('os-hosts',
diff --git a/nova/api/openstack/compute/contrib/keypairs.py b/nova/api/openstack/compute/contrib/keypairs.py
index 504539d55..7cd919673 100644
--- a/nova/api/openstack/compute/contrib/keypairs.py
+++ b/nova/api/openstack/compute/contrib/keypairs.py
@@ -31,6 +31,9 @@ from nova import db
from nova import exception
+authorize = extensions.extension_authorizer('compute', 'keypairs')
+
+
class KeypairTemplate(xmlutil.TemplateBuilder):
def construct(self):
return xmlutil.MasterTemplate(xmlutil.make_flat_dict('keypair'), 1)
@@ -77,6 +80,7 @@ class KeypairController(object):
"""
context = req.environ['nova.context']
+ authorize(context)
params = body['keypair']
name = params['name']
@@ -109,6 +113,7 @@ class KeypairController(object):
Delete a keypair with a given name
"""
context = req.environ['nova.context']
+ authorize(context)
db.key_pair_destroy(context, context.user_id, id)
return webob.Response(status_int=202)
@@ -118,6 +123,7 @@ class KeypairController(object):
List of keypairs for a user
"""
context = req.environ['nova.context']
+ authorize(context)
key_pairs = db.key_pair_get_all_by_user(context, context.user_id)
rval = []
for key_pair in key_pairs:
diff --git a/nova/api/openstack/compute/contrib/multinic.py b/nova/api/openstack/compute/contrib/multinic.py
index eea4532df..a3b4a8dc8 100644
--- a/nova/api/openstack/compute/contrib/multinic.py
+++ b/nova/api/openstack/compute/contrib/multinic.py
@@ -26,6 +26,7 @@ from nova import log as logging
LOG = logging.getLogger("nova.api.openstack.compute.contrib.multinic")
+authorize = extensions.extension_authorizer('compute', 'multinic')
class MultinicController(wsgi.Controller):
@@ -43,13 +44,14 @@ class MultinicController(wsgi.Controller):
@wsgi.action('addFixedIp')
def _add_fixed_ip(self, req, id, body):
"""Adds an IP on a given network to an instance."""
+ context = req.environ['nova.context']
+ authorize(context)
# Validate the input entity
if 'networkId' not in body['addFixedIp']:
msg = _("Missing 'networkId' argument for addFixedIp")
raise exc.HTTPUnprocessableEntity(explanation=msg)
- context = req.environ['nova.context']
instance = self._get_instance(context, id)
network_id = body['addFixedIp']['networkId']
self.compute_api.add_fixed_ip(context, instance, network_id)
@@ -58,13 +60,14 @@ class MultinicController(wsgi.Controller):
@wsgi.action('removeFixedIp')
def _remove_fixed_ip(self, req, id, body):
"""Removes an IP from an instance."""
+ context = req.environ['nova.context']
+ authorize(context)
# Validate the input entity
if 'address' not in body['removeFixedIp']:
msg = _("Missing 'address' argument for removeFixedIp")
raise exc.HTTPUnprocessableEntity(explanation=msg)
- context = req.environ['nova.context']
instance = self._get_instance(context, id)
address = body['removeFixedIp']['address']
diff --git a/nova/api/openstack/compute/contrib/networks.py b/nova/api/openstack/compute/contrib/networks.py
index f2381a19d..765a1d2fe 100644
--- a/nova/api/openstack/compute/contrib/networks.py
+++ b/nova/api/openstack/compute/contrib/networks.py
@@ -28,6 +28,7 @@ import nova.network.api
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.api.openstack.compute.contrib.networks')
+authorize = extensions.extension_authorizer('compute', 'networks')
def network_dict(network):
@@ -65,6 +66,7 @@ class NetworkController(object):
def _disassociate(self, request, network_id, body):
context = request.environ['nova.context']
+ authorize(context)
LOG.debug(_("Disassociating network with id %s" % network_id))
try:
self.network_api.disassociate(context, network_id)
@@ -74,12 +76,14 @@ class NetworkController(object):
def index(self, req):
context = req.environ['nova.context']
+ authorize(context)
networks = self.network_api.get_all(context)
result = [network_dict(net_ref) for net_ref in networks]
return {'networks': result}
def show(self, req, id):
context = req.environ['nova.context']
+ authorize(context)
LOG.debug(_("Showing network with id %s") % id)
try:
network = self.network_api.get(context, id)
@@ -89,6 +93,7 @@ class NetworkController(object):
def delete(self, req, id):
context = req.environ['nova.context']
+ authorize(context)
LOG.info(_("Deleting network with id %s") % id)
try:
self.network_api.delete(context, id)
@@ -107,7 +112,6 @@ class Networks(extensions.ExtensionDescriptor):
alias = "os-networks"
namespace = "http://docs.openstack.org/compute/ext/networks/api/v1.1"
updated = "2011-12-23 00:00:00"
- admin_only = True
def get_resources(self):
member_actions = {'action': 'POST'}
diff --git a/nova/api/openstack/compute/contrib/quotas.py b/nova/api/openstack/compute/contrib/quotas.py
index 5e4a20568..ce466af3f 100644
--- a/nova/api/openstack/compute/contrib/quotas.py
+++ b/nova/api/openstack/compute/contrib/quotas.py
@@ -25,6 +25,9 @@ from nova import exception
from nova import quota
+authorize = extensions.extension_authorizer('compute', 'quotas')
+
+
quota_resources = ['metadata_items', 'injected_file_content_bytes',
'volumes', 'gigabytes', 'ram', 'floating_ips', 'instances',
'injected_files', 'cores']
@@ -57,6 +60,7 @@ class QuotaSetsController(object):
@wsgi.serializers(xml=QuotaTemplate)
def show(self, req, id):
context = req.environ['nova.context']
+ authorize(context)
try:
db.sqlalchemy.api.authorize_project_context(context, id)
return self._format_quota_set(id,
@@ -67,6 +71,7 @@ class QuotaSetsController(object):
@wsgi.serializers(xml=QuotaTemplate)
def update(self, req, id, body):
context = req.environ['nova.context']
+ authorize(context)
project_id = id
for key in body['quota_set'].keys():
if key in quota_resources:
@@ -80,6 +85,7 @@ class QuotaSetsController(object):
return {'quota_set': quota.get_project_quotas(context, project_id)}
def defaults(self, req, id):
+ authorize(req.environ['nova.context'])
return self._format_quota_set(id, quota._get_default_quotas())
diff --git a/nova/api/openstack/compute/contrib/rescue.py b/nova/api/openstack/compute/contrib/rescue.py
index b0d5c6f97..e5fbb8388 100644
--- a/nova/api/openstack/compute/contrib/rescue.py
+++ b/nova/api/openstack/compute/contrib/rescue.py
@@ -28,6 +28,7 @@ from nova import utils
FLAGS = flags.FLAGS
LOG = logging.getLogger("nova.api.openstack.compute.contrib.rescue")
+authorize = exts.extension_authorizer('compute', 'rescue')
class RescueController(wsgi.Controller):
@@ -47,6 +48,7 @@ class RescueController(wsgi.Controller):
def _rescue(self, req, id, body):
"""Rescue an instance."""
context = req.environ["nova.context"]
+ authorize(context)
if body['rescue'] and 'adminPass' in body['rescue']:
password = body['rescue']['adminPass']
@@ -62,6 +64,7 @@ class RescueController(wsgi.Controller):
def _unrescue(self, req, id, body):
"""Unrescue an instance."""
context = req.environ["nova.context"]
+ authorize(context)
instance = self._get_instance(context, id)
self.compute_api.unrescue(context, instance)
return webob.Response(status_int=202)
diff --git a/nova/api/openstack/compute/contrib/security_groups.py b/nova/api/openstack/compute/contrib/security_groups.py
index 23b741145..45d72bf61 100644
--- a/nova/api/openstack/compute/contrib/security_groups.py
+++ b/nova/api/openstack/compute/contrib/security_groups.py
@@ -35,6 +35,7 @@ from nova import utils
LOG = logging.getLogger("nova.api.openstack.compute.contrib.security_groups")
FLAGS = flags.FLAGS
+authorize = extensions.extension_authorizer('compute', 'security_groups')
def make_rule(elem):
@@ -223,6 +224,7 @@ class SecurityGroupController(object):
def show(self, req, id):
"""Return data about the given security group."""
context = req.environ['nova.context']
+ authorize(context)
security_group = self._get_security_group(context, id)
return {'security_group': self._format_security_group(context,
security_group)}
@@ -230,6 +232,7 @@ class SecurityGroupController(object):
def delete(self, req, id):
"""Delete a security group."""
context = req.environ['nova.context']
+ authorize(context)
security_group = self._get_security_group(context, id)
LOG.audit(_("Delete security group %s"), id, context=context)
db.security_group_destroy(context, security_group.id)
@@ -240,6 +243,7 @@ class SecurityGroupController(object):
def index(self, req):
"""Returns a list of security groups"""
context = req.environ['nova.context']
+ authorize(context)
self.compute_api.ensure_default_security_group(context)
groups = db.security_group_get_by_project(context,
@@ -257,6 +261,7 @@ class SecurityGroupController(object):
def create(self, req, body):
"""Creates a new security group."""
context = req.environ['nova.context']
+ authorize(context)
if not body:
raise exc.HTTPUnprocessableEntity()
@@ -313,6 +318,7 @@ class SecurityGroupRulesController(SecurityGroupController):
@wsgi.deserializers(xml=SecurityGroupRulesXMLDeserializer)
def create(self, req, body):
context = req.environ['nova.context']
+ authorize(context)
if not body:
raise exc.HTTPUnprocessableEntity()
@@ -471,6 +477,7 @@ class SecurityGroupRulesController(SecurityGroupController):
def delete(self, req, id):
context = req.environ['nova.context']
+ authorize(context)
self.compute_api.ensure_default_security_group(context)
try:
@@ -505,6 +512,7 @@ class SecurityGroupActionController(wsgi.Controller):
@wsgi.action('addSecurityGroup')
def _addSecurityGroup(self, req, id, body):
context = req.environ['nova.context']
+ authorize(context)
try:
body = body['addSecurityGroup']
@@ -535,6 +543,7 @@ class SecurityGroupActionController(wsgi.Controller):
@wsgi.action('removeSecurityGroup')
def _removeSecurityGroup(self, req, id, body):
context = req.environ['nova.context']
+ authorize(context)
try:
body = body['removeSecurityGroup']
diff --git a/nova/api/openstack/compute/contrib/server_action_list.py b/nova/api/openstack/compute/contrib/server_action_list.py
index 436758572..24d3595d4 100644
--- a/nova/api/openstack/compute/contrib/server_action_list.py
+++ b/nova/api/openstack/compute/contrib/server_action_list.py
@@ -23,6 +23,7 @@ from nova import exception
sa_nsmap = {None: wsgi.XMLNS_V11}
+authorize = extensions.extension_authorizer('compute', 'server_action_list')
class ServerActionsTemplate(xmlutil.TemplateBuilder):
@@ -39,6 +40,7 @@ class ServerActionListController(object):
@wsgi.serializers(xml=ServerActionsTemplate)
def index(self, req, server_id):
context = req.environ["nova.context"]
+ authorize(context)
compute_api = compute.API()
try:
@@ -66,7 +68,6 @@ class Server_action_list(extensions.ExtensionDescriptor):
namespace = "http://docs.openstack.org/compute/ext/" \
"server-actions-list/api/v1.1"
updated = "2011-12-21T00:00:00+00:00"
- admin_only = True
def get_resources(self):
parent_def = {'member_name': 'server', 'collection_name': 'servers'}
diff --git a/nova/api/openstack/compute/contrib/server_diagnostics.py b/nova/api/openstack/compute/contrib/server_diagnostics.py
index 11d1affaf..49afcac01 100644
--- a/nova/api/openstack/compute/contrib/server_diagnostics.py
+++ b/nova/api/openstack/compute/contrib/server_diagnostics.py
@@ -23,6 +23,7 @@ from nova import exception
from nova.scheduler import api as scheduler_api
+authorize = extensions.extension_authorizer('compute', 'server_diagnostics')
sd_nsmap = {None: wsgi.XMLNS_V11}
@@ -41,6 +42,7 @@ class ServerDiagnosticsController(object):
@scheduler_api.redirect_handler
def index(self, req, server_id):
context = req.environ["nova.context"]
+ authorize(context)
compute_api = compute.API()
try:
instance = compute_api.get(context, id)
@@ -58,7 +60,6 @@ class Server_diagnostics(extensions.ExtensionDescriptor):
namespace = "http://docs.openstack.org/compute/ext/" \
"server-diagnostics/api/v1.1"
updated = "2011-12-21T00:00:00+00:00"
- admin_only = True
def get_resources(self):
parent_def = {'member_name': 'server', 'collection_name': 'servers'}
diff --git a/nova/api/openstack/compute/contrib/simple_tenant_usage.py b/nova/api/openstack/compute/contrib/simple_tenant_usage.py
index 85ea9a859..8e4201546 100644
--- a/nova/api/openstack/compute/contrib/simple_tenant_usage.py
+++ b/nova/api/openstack/compute/contrib/simple_tenant_usage.py
@@ -29,6 +29,7 @@ from nova import flags
FLAGS = flags.FLAGS
+authorize = extensions.extension_authorizer('compute', 'simple_tenant_usage')
def make_usage(elem):
@@ -211,6 +212,7 @@ class SimpleTenantUsageController(object):
def index(self, req):
"""Retrive tenant_usage for all tenants"""
context = req.environ['nova.context']
+ authorize(context)
if not context.is_admin:
return webob.Response(status_int=403)
@@ -227,6 +229,7 @@ class SimpleTenantUsageController(object):
"""Retrive tenant_usage for a specified tenant"""
tenant_id = id
context = req.environ['nova.context']
+ authorize(context)
if not context.is_admin:
if tenant_id != context.project_id:
@@ -253,7 +256,6 @@ class Simple_tenant_usage(extensions.ExtensionDescriptor):
namespace = "http://docs.openstack.org/compute/ext/" \
"os-simple-tenant-usage/api/v1.1"
updated = "2011-08-19T00:00:00+00:00"
- admin_only = True
def get_resources(self):
resources = []
diff --git a/nova/api/openstack/compute/contrib/users.py b/nova/api/openstack/compute/contrib/users.py
index 55dba02e4..b2a97f327 100644
--- a/nova/api/openstack/compute/contrib/users.py
+++ b/nova/api/openstack/compute/contrib/users.py
@@ -27,6 +27,7 @@ from nova import log as logging
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.api.openstack.users')
+authorize = extensions.extension_authorizer('compute', 'users')
def make_user(elem):
@@ -65,15 +66,10 @@ class Controller(object):
def __init__(self):
self.manager = manager.AuthManager()
- def _check_admin(self, context):
- """We cannot depend on the db layer to check for admin access
- for the auth manager, so we do it here"""
- if not context.is_admin:
- raise exception.AdminRequired()
-
@wsgi.serializers(xml=UsersTemplate)
def index(self, req):
"""Return all users in brief"""
+ authorize(req.environ['nova.context'])
users = self.manager.get_users()
users = common.limited(users, req)
users = [_translate_keys(user) for user in users]
@@ -87,6 +83,7 @@ class Controller(object):
@wsgi.serializers(xml=UserTemplate)
def show(self, req, id):
"""Return data about the given user id"""
+ authorize(req.environ['nova.context'])
#NOTE(justinsb): The drivers are a little inconsistent in how they
# deal with "NotFound" - some throw, some return None.
@@ -101,13 +98,13 @@ class Controller(object):
return dict(user=_translate_keys(user))
def delete(self, req, id):
- self._check_admin(req.environ['nova.context'])
+ authorize(req.environ['nova.context'])
self.manager.delete_user(id)
return {}
@wsgi.serializers(xml=UserTemplate)
def create(self, req, body):
- self._check_admin(req.environ['nova.context'])
+ authorize(req.environ['nova.context'])
is_admin = body['user'].get('admin') in ('T', 'True', True)
name = body['user'].get('name')
access = body['user'].get('access')
@@ -117,7 +114,7 @@ class Controller(object):
@wsgi.serializers(xml=UserTemplate)
def update(self, req, id, body):
- self._check_admin(req.environ['nova.context'])
+ authorize(req.environ['nova.context'])
is_admin = body['user'].get('admin')
if is_admin is not None:
is_admin = is_admin in ('T', 'True', True)
@@ -134,7 +131,6 @@ class Users(extensions.ExtensionDescriptor):
alias = "os-users"
namespace = "http://docs.openstack.org/compute/ext/users/api/v1.1"
updated = "2011-08-08T00:00:00+00:00"
- admin_only = True
def get_resources(self):
coll_actions = {'detail': 'GET'}
diff --git a/nova/api/openstack/compute/contrib/virtual_interfaces.py b/nova/api/openstack/compute/contrib/virtual_interfaces.py
index ea37c4d97..e8da23c00 100644
--- a/nova/api/openstack/compute/contrib/virtual_interfaces.py
+++ b/nova/api/openstack/compute/contrib/virtual_interfaces.py
@@ -25,6 +25,7 @@ from nova import network
LOG = logging.getLogger("nova.api.openstack.compute."
"contrib.virtual_interfaces")
+authorize = extensions.extension_authorizer('compute', 'virtual_interfaces')
vif_nsmap = {None: wsgi.XMLNS_V11}
@@ -68,6 +69,7 @@ class ServerVirtualInterfaceController(object):
@wsgi.serializers(xml=VirtualInterfaceTemplate)
def index(self, req, server_id):
"""Returns the list of VIFs for a given instance."""
+ authorize(req.environ['nova.context'])
return self._items(req, server_id,
entity_maker=_translate_vif_summary_view)
diff --git a/nova/api/openstack/compute/contrib/virtual_storage_arrays.py b/nova/api/openstack/compute/contrib/virtual_storage_arrays.py
index 10e8a1001..ed4b12a92 100644
--- a/nova/api/openstack/compute/contrib/virtual_storage_arrays.py
+++ b/nova/api/openstack/compute/contrib/virtual_storage_arrays.py
@@ -36,9 +36,11 @@ from nova import log as logging
from nova import vsa
from nova import volume
-FLAGS = flags.FLAGS
+FLAGS = flags.FLAGS
LOG = logging.getLogger("nova.api.openstack.compute.contrib.vsa")
+authorize = extensions.extension_authorizer('compute',
+ 'virtual_storage_arrays')
def _vsa_view(context, vsa, details=False, instances=None):
@@ -124,6 +126,7 @@ class VsaController(object):
def _items(self, req, details):
"""Return summary or detailed list of VSAs."""
context = req.environ['nova.context']
+ authorize(context)
vsas = self.vsa_api.get_all(context)
limited_list = common.limited(vsas, req)
@@ -147,6 +150,7 @@ class VsaController(object):
def show(self, req, id):
"""Return data about the given VSA."""
context = req.environ['nova.context']
+ authorize(context)
try:
vsa = self.vsa_api.get(context, vsa_id=id)
@@ -160,6 +164,7 @@ class VsaController(object):
def create(self, req, body):
"""Create a new VSA."""
context = req.environ['nova.context']
+ authorize(context)
if not body or 'vsa' not in body:
LOG.debug(_("No body provided"), context=context)
@@ -193,6 +198,7 @@ class VsaController(object):
def delete(self, req, id):
"""Delete a VSA."""
context = req.environ['nova.context']
+ authorize(context)
LOG.audit(_("Delete VSA with id: %s"), id, context=context)
@@ -206,6 +212,7 @@ class VsaController(object):
auto or manually associate an IP to VSA
"""
context = req.environ['nova.context']
+ authorize(context)
if body is None:
ip = 'auto'
@@ -234,6 +241,7 @@ class VsaController(object):
auto or manually associate an IP to VSA
"""
context = req.environ['nova.context']
+ authorize(context)
if body is None:
ip = 'auto'
@@ -293,6 +301,7 @@ class VsaVolumeDriveController(volumes.VolumeController):
def _items(self, req, vsa_id, details):
"""Return summary or detailed list of volumes for particular VSA."""
context = req.environ['nova.context']
+ authorize(context)
vols = self.volume_api.get_all(context,
search_opts={'metadata': {self.direction: str(vsa_id)}})
@@ -317,6 +326,7 @@ class VsaVolumeDriveController(volumes.VolumeController):
"""Create a new volume from VSA."""
LOG.audit(_("Create. vsa_id=%(vsa_id)s, body=%(body)s"), locals())
context = req.environ['nova.context']
+ authorize(context)
if not body:
raise exc.HTTPUnprocessableEntity()
@@ -345,6 +355,7 @@ class VsaVolumeDriveController(volumes.VolumeController):
def update(self, req, vsa_id, id, body):
"""Update a volume."""
context = req.environ['nova.context']
+ authorize(context)
try:
self._check_volume_ownership(context, vsa_id, id)
@@ -380,6 +391,7 @@ class VsaVolumeDriveController(volumes.VolumeController):
def delete(self, req, vsa_id, id):
"""Delete a volume."""
context = req.environ['nova.context']
+ authorize(context)
LOG.audit(_("Delete. vsa_id=%(vsa_id)s, id=%(id)s"), locals())
@@ -395,6 +407,7 @@ class VsaVolumeDriveController(volumes.VolumeController):
def show(self, req, vsa_id, id):
"""Return data about the given volume."""
context = req.environ['nova.context']
+ authorize(context)
LOG.audit(_("Show. vsa_id=%(vsa_id)s, id=%(id)s"), locals())
diff --git a/nova/api/openstack/compute/contrib/volumes.py b/nova/api/openstack/compute/contrib/volumes.py
index 83e67102b..c3ba33eef 100644
--- a/nova/api/openstack/compute/contrib/volumes.py
+++ b/nova/api/openstack/compute/contrib/volumes.py
@@ -32,9 +32,8 @@ from nova.volume import volume_types
LOG = logging.getLogger("nova.api.openstack.compute.contrib.volumes")
-
-
FLAGS = flags.FLAGS
+authorize = extensions.extension_authorizer('compute', 'volumes')
def _translate_volume_detail_view(context, vol):
@@ -130,6 +129,7 @@ class VolumeController(object):
def show(self, req, id):
"""Return data about the given volume."""
context = req.environ['nova.context']
+ authorize(context)
try:
vol = self.volume_api.get(context, id)
@@ -141,6 +141,7 @@ class VolumeController(object):
def delete(self, req, id):
"""Delete a volume."""
context = req.environ['nova.context']
+ authorize(context)
LOG.audit(_("Delete volume with id: %s"), id, context=context)
@@ -164,6 +165,7 @@ class VolumeController(object):
def _items(self, req, entity_maker):
"""Returns a list of volumes, transformed through entity_maker."""
context = req.environ['nova.context']
+ authorize(context)
volumes = self.volume_api.get_all(context)
limited_list = common.limited(volumes, req)
@@ -174,6 +176,7 @@ class VolumeController(object):
def create(self, req, body):
"""Creates a new volume."""
context = req.environ['nova.context']
+ authorize(context)
if not body:
raise exc.HTTPUnprocessableEntity()
@@ -289,6 +292,7 @@ class VolumeAttachmentController(object):
def show(self, req, server_id, id):
"""Return data about the given volume attachment."""
context = req.environ['nova.context']
+ authorize(context)
volume_id = id
try:
@@ -309,6 +313,7 @@ class VolumeAttachmentController(object):
def create(self, req, server_id, body):
"""Attach a volume to an instance."""
context = req.environ['nova.context']
+ authorize(context)
if not body:
raise exc.HTTPUnprocessableEntity()
@@ -350,6 +355,7 @@ class VolumeAttachmentController(object):
def delete(self, req, server_id, id):
"""Detach a volume from an instance."""
context = req.environ['nova.context']
+ authorize(context)
volume_id = id
LOG.audit(_("Detach volume %s"), volume_id, context=context)
@@ -372,6 +378,7 @@ class VolumeAttachmentController(object):
def _items(self, req, server_id, entity_maker):
"""Returns a list of attachments, transformed through entity_maker."""
context = req.environ['nova.context']
+ authorize(context)
try:
instance = self.compute_api.get(context, server_id)
@@ -452,6 +459,7 @@ class SnapshotController(object):
def show(self, req, id):
"""Return data about the given snapshot."""
context = req.environ['nova.context']
+ authorize(context)
try:
vol = self.volume_api.get_snapshot(context, id)
@@ -463,6 +471,7 @@ class SnapshotController(object):
def delete(self, req, id):
"""Delete a snapshot."""
context = req.environ['nova.context']
+ authorize(context)
LOG.audit(_("Delete snapshot with id: %s"), id, context=context)
@@ -485,6 +494,7 @@ class SnapshotController(object):
def _items(self, req, entity_maker):
"""Returns a list of snapshots, transformed through entity_maker."""
context = req.environ['nova.context']
+ authorize(context)
snapshots = self.volume_api.get_all_snapshots(context)
limited_list = common.limited(snapshots, req)
@@ -495,6 +505,7 @@ class SnapshotController(object):
def create(self, req, body):
"""Creates a new snapshot."""
context = req.environ['nova.context']
+ authorize(context)
if not body:
return exc.HTTPUnprocessableEntity()
diff --git a/nova/api/openstack/compute/contrib/volumetypes.py b/nova/api/openstack/compute/contrib/volumetypes.py
index bf249f3f8..cbc205ea7 100644
--- a/nova/api/openstack/compute/contrib/volumetypes.py
+++ b/nova/api/openstack/compute/contrib/volumetypes.py
@@ -27,6 +27,9 @@ from nova import exception
from nova.volume import volume_types
+authorize = extensions.extension_authorizer('compute', 'volumetypes')
+
+
def make_voltype(elem):
elem.set('id')
elem.set('name')
@@ -57,12 +60,14 @@ class VolumeTypesController(object):
def index(self, req):
""" Returns the list of volume types """
context = req.environ['nova.context']
+ authorize(context)
return volume_types.get_all_types(context)
@wsgi.serializers(xml=VolumeTypeTemplate)
def create(self, req, body):
"""Creates a new volume type."""
context = req.environ['nova.context']
+ authorize(context)
if not body or body == "":
raise exc.HTTPUnprocessableEntity()
@@ -91,6 +96,7 @@ class VolumeTypesController(object):
def show(self, req, id):
""" Return a single volume type item """
context = req.environ['nova.context']
+ authorize(context)
try:
vol_type = volume_types.get_volume_type(context, id)
@@ -102,6 +108,7 @@ class VolumeTypesController(object):
def delete(self, req, id):
""" Deletes an existing volume type """
context = req.environ['nova.context']
+ authorize(context)
try:
vol_type = volume_types.get_volume_type(context, id)
@@ -155,12 +162,14 @@ class VolumeTypeExtraSpecsController(object):
def index(self, req, vol_type_id):
""" Returns the list of extra specs for a given volume type """
context = req.environ['nova.context']
+ authorize(context)
return self._get_extra_specs(context, vol_type_id)
@wsgi.serializers(xml=VolumeTypeExtraSpecsTemplate)
def create(self, req, vol_type_id, body):
- self._check_body(body)
context = req.environ['nova.context']
+ authorize(context)
+ self._check_body(body)
specs = body.get('extra_specs')
try:
db.volume_type_extra_specs_update_or_create(context,
@@ -172,8 +181,9 @@ class VolumeTypeExtraSpecsController(object):
@wsgi.serializers(xml=VolumeTypeExtraSpecTemplate)
def update(self, req, vol_type_id, id, body):
- self._check_body(body)
context = req.environ['nova.context']
+ authorize(context)
+ self._check_body(body)
if not id in body:
expl = _('Request body and URI mismatch')
raise exc.HTTPBadRequest(explanation=expl)
@@ -193,6 +203,7 @@ class VolumeTypeExtraSpecsController(object):
def show(self, req, vol_type_id, id):
""" Return a single extra spec item """
context = req.environ['nova.context']
+ authorize(context)
specs = self._get_extra_specs(context, vol_type_id)
if id in specs['extra_specs']:
return {id: specs['extra_specs'][id]}
@@ -202,6 +213,7 @@ class VolumeTypeExtraSpecsController(object):
def delete(self, req, vol_type_id, id):
""" Deletes an existing extra spec """
context = req.environ['nova.context']
+ authorize(context)
db.volume_type_extra_specs_delete(context, vol_type_id, id)
def _handle_quota_error(self, error):
diff --git a/nova/api/openstack/compute/contrib/zones.py b/nova/api/openstack/compute/contrib/zones.py
index 539833ee2..fac3d7188 100644
--- a/nova/api/openstack/compute/contrib/zones.py
+++ b/nova/api/openstack/compute/contrib/zones.py
@@ -34,6 +34,7 @@ import nova.scheduler.api
LOG = logging.getLogger("nova.api.openstack.compute.contrib.zones")
FLAGS = flags.FLAGS
+authorize = extensions.extension_authorizer('compute', 'zones')
class CapabilitySelector(object):
@@ -117,6 +118,7 @@ class Controller(object):
@wsgi.serializers(xml=ZonesTemplate)
def index(self, req):
"""Return all zones in brief"""
+ authorize(req.environ['nova.context'])
# Ask the ZoneManager in the Scheduler for most recent data,
# or fall-back to the database ...
items = nova.scheduler.api.get_zone_list(req.environ['nova.context'])
@@ -133,6 +135,7 @@ class Controller(object):
def info(self, req):
"""Return name and capabilities for this zone."""
context = req.environ['nova.context']
+ authorize(context)
zone_capabs = nova.scheduler.api.get_zone_capabilities(context)
# NOTE(comstud): This should probably return, instead:
# {'zone': {'name': FLAGS.zone_name,
@@ -143,13 +146,15 @@ class Controller(object):
@wsgi.serializers(xml=ZoneTemplate)
def show(self, req, id):
"""Return data about the given zone id"""
- zone_id = int(id)
context = req.environ['nova.context']
+ authorize(context)
+ zone_id = int(id)
zone = nova.scheduler.api.zone_get(context, zone_id)
return dict(zone=_scrub_zone(zone))
def delete(self, req, id):
"""Delete a child zone entry."""
+ authorize(req.environ['nova.context'])
zone_id = int(id)
nova.scheduler.api.zone_delete(req.environ['nova.context'], zone_id)
return {}
@@ -159,6 +164,7 @@ class Controller(object):
def create(self, req, body):
"""Create a child zone entry."""
context = req.environ['nova.context']
+ authorize(context)
zone = nova.scheduler.api.zone_create(context, body["zone"])
return dict(zone=_scrub_zone(zone))
@@ -166,6 +172,7 @@ class Controller(object):
def update(self, req, id, body):
"""Update a child zone entry."""
context = req.environ['nova.context']
+ authorize(context)
zone_id = int(id)
zone = nova.scheduler.api.zone_update(context, zone_id, body["zone"])
return dict(zone=_scrub_zone(zone))
@@ -175,9 +182,10 @@ class Controller(object):
def select(self, req, body):
"""Returns a weighted list of costs to create instances
of desired capabilities."""
- ctx = req.environ['nova.context']
+ context = req.environ['nova.context']
+ authorize(context)
specs = json.loads(body)
- build_plan = nova.scheduler.api.select(ctx, specs=specs)
+ build_plan = nova.scheduler.api.select(context, specs=specs)
cooked = self._scrub_build_plan(build_plan)
return {"weights": cooked}
@@ -205,7 +213,6 @@ class Zones(extensions.ExtensionDescriptor):
alias = "os-zones"
namespace = "http://docs.openstack.org/compute/ext/zones/api/v1.1"
updated = "2011-09-21T00:00:00+00:00"
- admin_only = True
def get_resources(self):
#NOTE(bcwaldon): This resource should be prefixed with 'os-'
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index ee7038c6e..d0e771e22 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -1170,7 +1170,7 @@ def create_resource():
def remove_invalid_options(context, search_options, allowed_search_options):
"""Remove search options that are not valid for non-admin API/context"""
- if FLAGS.allow_admin_api and context.is_admin:
+ if context.is_admin:
# Allow all options
return
# Otherwise, strip out all unknown options
diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py
index 4b8da21ed..bf415765c 100644
--- a/nova/api/openstack/extensions.py
+++ b/nova/api/openstack/extensions.py
@@ -16,8 +16,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+import functools
import os
import routes
+
import webob.dec
import webob.exc
@@ -27,13 +29,12 @@ from nova.api.openstack import xmlutil
from nova import exception
from nova import flags
from nova import log as logging
+import nova.policy
from nova import utils
from nova import wsgi as base_wsgi
LOG = logging.getLogger('nova.api.openstack.extensions')
-
-
FLAGS = flags.FLAGS
@@ -61,10 +62,6 @@ class ExtensionDescriptor(object):
# '2011-01-22T13:25:27-06:00'
updated = None
- # This attribute causes the extension to load only when
- # the admin api is enabled
- admin_only = False
-
def __init__(self, ext_mgr):
"""Register extension with the extension manager."""
@@ -246,15 +243,10 @@ class ExtensionManager(object):
' '.join(extension.__doc__.strip().split()))
LOG.debug(_('Ext namespace: %s'), extension.namespace)
LOG.debug(_('Ext updated: %s'), extension.updated)
- LOG.debug(_('Ext admin_only: %s'), extension.admin_only)
except AttributeError as ex:
LOG.exception(_("Exception loading extension: %s"), unicode(ex))
return False
- # Don't load admin api extensions if the admin api isn't enabled
- if not FLAGS.allow_admin_api and extension.admin_only:
- return False
-
return True
def load_extension(self, ext_factory):
@@ -384,3 +376,22 @@ def load_standard_extensions(ext_mgr, logger, path, package):
# Update the list of directories we'll explore...
dirnames[:] = subdirs
+
+
+def extension_authorizer(api_name, extension_name):
+ def authorize(context):
+ action = '%s_extension:%s' % (api_name, extension_name)
+ nova.policy.enforce(context, action, {})
+ return authorize
+
+
+def soft_extension_authorizer(api_name, extension_name):
+ hard_authorize = extension_authorizer(api_name, extension_name)
+
+ def authorize(context):
+ try:
+ hard_authorize(context)
+ return True
+ except exception.NotAuthorized:
+ return False
+ return authorize