diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-01-24 19:32:49 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-01-24 19:32:49 +0000 |
| commit | 8dfd968e83cbcdc0796caa44289144d38a6a5ce8 (patch) | |
| tree | e0e2e571a9aae49fc71736ad034d8fb6ed31b0b0 | |
| parent | c88771d8202f9c1c3f7a7260dea200d902b3c3aa (diff) | |
| parent | 9cb5f547dc6f3242edf393928dbc14b7cbfbbdd4 (diff) | |
| download | nova-8dfd968e83cbcdc0796caa44289144d38a6a5ce8.tar.gz nova-8dfd968e83cbcdc0796caa44289144d38a6a5ce8.tar.xz nova-8dfd968e83cbcdc0796caa44289144d38a6a5ce8.zip | |
Merge "Remove admin_only ext attr in favor of authz"
51 files changed, 326 insertions, 233 deletions
diff --git a/doc/source/devref/distributed_scheduler.rst b/doc/source/devref/distributed_scheduler.rst index 7a631d69f..a185095be 100644 --- a/doc/source/devref/distributed_scheduler.rst +++ b/doc/source/devref/distributed_scheduler.rst @@ -164,14 +164,12 @@ All this Zone and Distributed Scheduler stuff can seem a little daunting to conf :: - --allow_admin_api=true --enable_zone_routing=true --zone_name=zone1 --build_plan_encryption_key=c286696d887c9aa0611bbb3e2025a45b --scheduler_driver=nova.scheduler.base_scheduler.BaseScheduler --default_host_filter=nova.scheduler.filters.AllHostsFilter -`--allow_admin_api` must be set for OS API to enable the new `/zones/*` commands. `--enable_zone_routing` must be set for OS API commands such as `create()`, `pause()` and `delete()` to get routed from Zone to Zone when looking for instances. `--zone_name` is only required in child Zones. The default Zone name is `nova`, but you may want to name your child Zones something useful. Duplicate Zone names are not an issue. `build_plan_encryption_key` is the SHA-256 key for encrypting/decrypting the Host information when it leaves a Zone. Be sure to change this key for each Zone you create. Do not duplicate keys. diff --git a/doc/source/devref/zone.rst b/doc/source/devref/zone.rst index 3dc0f80fd..241cbf46c 100644 --- a/doc/source/devref/zone.rst +++ b/doc/source/devref/zone.rst @@ -55,8 +55,6 @@ Zone administrative operations are usually done using python-novaclient_ .. _python-novaclient: https://github.com/rackspace/python-novaclient -In order to use the Zone operations, be sure to enable administrator operations in OpenStack API by setting the `--allow_admin_api=true` flag. - Finally you need to enable Zone Forwarding. This will be used by the Distributed Scheduler initiative currently underway. Set `--enable_zone_routing=true` to enable this feature. Find out about this Zone diff --git a/etc/nova/policy.json b/etc/nova/policy.json index 7d97c3be1..abf8908f6 100644 --- a/etc/nova/policy.json +++ b/etc/nova/policy.json @@ -9,6 +9,38 @@ "compute:get_all": [], + "admin_api": [["role:admin"]], + "compute_extension:accounts": [["rule:admin_api"]], + "compute_extension:admin_actions": [["rule:admin_api"]], + "compute_extension:cloudpipe": [], + "compute_extension:console_output": [], + "compute_extension:consoles": [], + "compute_extension:createserverext": [], + "compute_extension:deferred_delete": [], + "compute_extension:disk_config": [], + "compute_extension:extended_status": [["rule:admin_api"]], + "compute_extension:flavorextraspecs": [], + "compute_extension:floating_ip_dns": [], + "compute_extension:floating_ip_pools": [], + "compute_extension:floating_ips": [], + "compute_extension:hosts": [["rule:admin_api"]], + "compute_extension:keypairs": [], + "compute_extension:multinic": [], + "compute_extension:networks": [["rule:admin_api"]], + "compute_extension:quotas": [], + "compute_extension:rescue": [], + "compute_extension:security_groups": [], + "compute_extension:server_action_list": [["rule:admin_api"]], + "compute_extension:server_diagnostics": [["rule:admin_api"]], + "compute_extension:simple_tenant_usage": [["rule:admin_api"]], + "compute_extension:users": [["rule:admin_api"]], + "compute_extension:virtual_interfaces": [], + "compute_extension:virtual_storage_arrays": [], + "compute_extension:volumes": [], + "compute_extension:volumetypes": [], + "compute_extension:zones": [], + + "volume:create": [], "volume:get_all": [], "volume:get_volume_metadata": [], 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 diff --git a/nova/tests/api/openstack/compute/contrib/test_accounts.py b/nova/tests/api/openstack/compute/contrib/test_accounts.py index dbf0e2600..6b820bd57 100644 --- a/nova/tests/api/openstack/compute/contrib/test_accounts.py +++ b/nova/tests/api/openstack/compute/contrib/test_accounts.py @@ -29,18 +29,12 @@ def fake_init(self): self.manager = fakes.FakeAuthManager() -def fake_admin_check(self, req): - return True - - class AccountsTest(test.TestCase): def setUp(self): super(AccountsTest, self).setUp() - self.flags(verbose=True, allow_admin_api=True) + self.flags(verbose=True) self.stubs.Set(accounts.Controller, '__init__', fake_init) - self.stubs.Set(accounts.Controller, '_check_admin', - fake_admin_check) fakes.FakeAuthManager.clear_fakes() fakes.FakeAuthDatabase.data = {} fakes.stub_out_networking(self.stubs) diff --git a/nova/tests/api/openstack/compute/contrib/test_admin_actions.py b/nova/tests/api/openstack/compute/contrib/test_admin_actions.py index 3878ce676..f572b12d9 100644 --- a/nova/tests/api/openstack/compute/contrib/test_admin_actions.py +++ b/nova/tests/api/openstack/compute/contrib/test_admin_actions.py @@ -79,7 +79,6 @@ class AdminActionsTest(test.TestCase): super(AdminActionsTest, self).setUp() self.stubs.Set(compute.API, 'get', fake_compute_api_get) self.UUID = utils.gen_uuid() - self.flags(allow_admin_api=True) for _method in self._methods: self.stubs.Set(compute.API, _method, fake_compute_api) @@ -122,8 +121,9 @@ class CreateBackupTests(test.TestCase): self.stubs.Set(compute.API, 'get', fake_compute_api_get) self.backup_stubs = fakes.stub_out_compute_api_backup(self.stubs) - self.flags(allow_admin_api=True) - self.app = compute_api.APIRouter() + router = compute_api.APIRouter() + ext_middleware = extensions.ExtensionMiddleware(router) + self.app = wsgi.LazySerializationMiddleware(ext_middleware) self.uuid = utils.gen_uuid() diff --git a/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py index 64b206aef..27341f199 100644 --- a/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py +++ b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py @@ -107,7 +107,6 @@ class CloudpipeTest(test.TestCase): def setUp(self): super(CloudpipeTest, self).setUp() - self.flags(allow_admin_api=True) self.app = fakes.wsgi_app() inner_app = compute.APIRouter() self.context = context.RequestContext('fake', 'fake', is_admin=True) diff --git a/nova/tests/api/openstack/compute/contrib/test_deferred_delete.py b/nova/tests/api/openstack/compute/contrib/test_deferred_delete.py index a864aa595..d02569e00 100644 --- a/nova/tests/api/openstack/compute/contrib/test_deferred_delete.py +++ b/nova/tests/api/openstack/compute/contrib/test_deferred_delete.py @@ -18,6 +18,7 @@ import webob from nova.api.openstack.compute.contrib import deferred_delete +import nova.context from nova import compute from nova import exception from nova import test @@ -34,7 +35,7 @@ class DeferredDeleteExtensionTest(test.TestCase): self.extension = deferred_delete.DeferredDeleteController() self.fake_input_dict = {} self.fake_uuid = 'fake_uuid' - self.fake_context = 'fake_context' + self.fake_context = nova.context.RequestContext('fake', 'fake') self.fake_req = FakeRequest(self.fake_context) def test_force_delete(self): diff --git a/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py b/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py index dc7f0cefa..738ab8290 100644 --- a/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py +++ b/nova/tests/api/openstack/compute/contrib/test_extendedstatus.py @@ -41,7 +41,6 @@ class ExtendedStatusTest(test.TestCase): self.uuid = '70f6db34-de8d-4fbd-aafb-4065bdfa6114' self.url = '/v2/fake/servers/%s' % self.uuid fakes.stub_out_nw_api(self.stubs) - self.flags(allow_admin_api=True) self.stubs.Set(compute.api.API, 'routing_get', fake_compute_get) def _make_request(self): diff --git a/nova/tests/api/openstack/compute/contrib/test_hosts.py b/nova/tests/api/openstack/compute/contrib/test_hosts.py index e6a91477e..af4818c90 100644 --- a/nova/tests/api/openstack/compute/contrib/test_hosts.py +++ b/nova/tests/api/openstack/compute/contrib/test_hosts.py @@ -94,17 +94,14 @@ class HostTestCase(test.TestCase): self.assertEqual(result_c2["status"], "disabled") def test_host_startup(self): - self.flags(allow_admin_api=True) result = self.controller.startup(self.req, "host_c1") self.assertEqual(result["power_action"], "startup") def test_host_shutdown(self): - self.flags(allow_admin_api=True) result = self.controller.shutdown(self.req, "host_c1") self.assertEqual(result["power_action"], "shutdown") def test_host_reboot(self): - self.flags(allow_admin_api=True) result = self.controller.reboot(self.req, "host_c1") self.assertEqual(result["power_action"], "reboot") diff --git a/nova/tests/api/openstack/compute/contrib/test_networks.py b/nova/tests/api/openstack/compute/contrib/test_networks.py index 0eefca652..ed928348e 100644 --- a/nova/tests/api/openstack/compute/contrib/test_networks.py +++ b/nova/tests/api/openstack/compute/contrib/test_networks.py @@ -92,7 +92,6 @@ class NetworksTest(test.TestCase): def setUp(self): super(NetworksTest, self).setUp() - self.flags(allow_admin_api=True) self.fake_network_api = FakeNetworkAPI() self.controller = networks.NetworkController(self.fake_network_api) fakes.stub_out_networking(self.stubs) diff --git a/nova/tests/api/openstack/compute/contrib/test_server_action_list.py b/nova/tests/api/openstack/compute/contrib/test_server_action_list.py index ffd4f744d..2a175f1dd 100644 --- a/nova/tests/api/openstack/compute/contrib/test_server_action_list.py +++ b/nova/tests/api/openstack/compute/contrib/test_server_action_list.py @@ -47,7 +47,6 @@ class ServerActionsTest(test.TestCase): def setUp(self): super(ServerActionsTest, self).setUp() - self.flags(allow_admin_api=True) self.flags(verbose=True) self.stubs.Set(nova.compute.API, 'get_actions', fake_get_actions) self.stubs.Set(nova.compute.API, 'get', fake_instance_get) diff --git a/nova/tests/api/openstack/compute/contrib/test_server_diagnostics.py b/nova/tests/api/openstack/compute/contrib/test_server_diagnostics.py index 688940e3d..b18b5018d 100644 --- a/nova/tests/api/openstack/compute/contrib/test_server_diagnostics.py +++ b/nova/tests/api/openstack/compute/contrib/test_server_diagnostics.py @@ -40,7 +40,6 @@ class ServerDiagnosticsTest(test.TestCase): def setUp(self): super(ServerDiagnosticsTest, self).setUp() - self.flags(allow_admin_api=True) self.flags(verbose=True) self.stubs.Set(nova.compute.API, 'get_diagnostics', fake_get_diagnostics) diff --git a/nova/tests/api/openstack/compute/contrib/test_simple_tenant_usage.py b/nova/tests/api/openstack/compute/contrib/test_simple_tenant_usage.py index b41773824..812aac297 100644 --- a/nova/tests/api/openstack/compute/contrib/test_simple_tenant_usage.py +++ b/nova/tests/api/openstack/compute/contrib/test_simple_tenant_usage.py @@ -88,7 +88,6 @@ class SimpleTenantUsageTest(test.TestCase): self.alt_user_context = context.RequestContext('fakeadmin_0', 'faketenant_1', is_admin=False) - FLAGS.allow_admin_api = True def test_verify_index(self): req = webob.Request.blank( diff --git a/nova/tests/api/openstack/compute/contrib/test_users.py b/nova/tests/api/openstack/compute/contrib/test_users.py index 5895f4f66..3dd0b3074 100644 --- a/nova/tests/api/openstack/compute/contrib/test_users.py +++ b/nova/tests/api/openstack/compute/contrib/test_users.py @@ -26,18 +26,12 @@ def fake_init(self): self.manager = fakes.FakeAuthManager() -def fake_admin_check(self, req): - return True - - class UsersTest(test.TestCase): def setUp(self): super(UsersTest, self).setUp() - self.flags(verbose=True, allow_admin_api=True) + self.flags(verbose=True) self.stubs.Set(users.Controller, '__init__', fake_init) - self.stubs.Set(users.Controller, '_check_admin', - fake_admin_check) fakes.FakeAuthManager.clear_fakes() fakes.FakeAuthManager.projects = dict(testacct=Project('testacct', 'testacct', diff --git a/nova/tests/api/openstack/compute/contrib/test_zones.py b/nova/tests/api/openstack/compute/contrib/test_zones.py index e23ea85e6..9f887cb0d 100644 --- a/nova/tests/api/openstack/compute/contrib/test_zones.py +++ b/nova/tests/api/openstack/compute/contrib/test_zones.py @@ -95,7 +95,6 @@ def zone_select(context, specs): class ZonesTest(test.TestCase): def setUp(self): super(ZonesTest, self).setUp() - self.flags(verbose=True, allow_admin_api=True) fakes.stub_out_networking(self.stubs) fakes.stub_out_rate_limiting(self.stubs) diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py index 796880e1f..54d0e4625 100644 --- a/nova/tests/api/openstack/compute/test_extensions.py +++ b/nova/tests/api/openstack/compute/test_extensions.py @@ -150,7 +150,6 @@ class ExtensionControllerTest(ExtensionTestCase): def setUp(self): super(ExtensionControllerTest, self).setUp() - self.flags(allow_admin_api=True) self.ext_list = [ "Accounts", "AdminActions", @@ -355,19 +354,6 @@ class InvalidExtension(object): alias = "THIRD" -class AdminExtension(base_extensions.ExtensionDescriptor): - """Admin-only extension""" - - name = "Admin Ext" - alias = "ADMIN" - namespace = "http://www.example.com/" - updated = "2011-01-22T13:25:27-06:00" - admin_only = True - - def __init__(self, *args, **kwargs): - pass - - class ExtensionManagerTest(ExtensionTestCase): response_body = "Try to say this Mr. Knox, sir..." @@ -388,22 +374,6 @@ class ExtensionManagerTest(ExtensionTestCase): self.assertTrue('FOXNSOX' in ext_mgr.extensions) self.assertTrue('THIRD' not in ext_mgr.extensions) - def test_admin_extensions(self): - self.flags(allow_admin_api=True) - app = compute.APIRouter() - ext_mgr = compute_extensions.ExtensionManager() - ext_mgr.register(AdminExtension()) - self.assertTrue('FOXNSOX' in ext_mgr.extensions) - self.assertTrue('ADMIN' in ext_mgr.extensions) - - def test_admin_extensions_no_admin_api(self): - self.flags(allow_admin_api=False) - app = compute.APIRouter() - ext_mgr = compute_extensions.ExtensionManager() - ext_mgr.register(AdminExtension()) - self.assertTrue('FOXNSOX' in ext_mgr.extensions) - self.assertTrue('ADMIN' not in ext_mgr.extensions) - class ActionExtensionTest(ExtensionTestCase): diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py index f545aeaec..c6c7fcc43 100644 --- a/nova/tests/api/openstack/compute/test_servers.py +++ b/nova/tests/api/openstack/compute/test_servers.py @@ -861,7 +861,6 @@ class ServersControllerTest(test.TestCase): return [fakes.stub_instance(100, uuid=server_uuid)] self.stubs.Set(nova.compute.API, 'get_all', fake_get_all) - self.flags(allow_admin_api=False) req = fakes.HTTPRequest.blank('/v2/fake/servers?image=12345') servers = self.controller.index(req)['servers'] @@ -878,7 +877,6 @@ class ServersControllerTest(test.TestCase): self.stubs.Set(nova.db, 'instance_get_all_by_filters', fake_get_all) - self.flags(allow_admin_api=True) req = fakes.HTTPRequest.blank('/v2/fake/servers?tenant_id=fake', use_admin_context=True) @@ -897,7 +895,6 @@ class ServersControllerTest(test.TestCase): return [fakes.stub_instance(100, uuid=server_uuid)] self.stubs.Set(nova.compute.API, 'get_all', fake_get_all) - self.flags(allow_admin_api=False) req = fakes.HTTPRequest.blank('/v2/fake/servers?flavor=12345') servers = self.controller.index(req)['servers'] @@ -915,7 +912,6 @@ class ServersControllerTest(test.TestCase): return [fakes.stub_instance(100, uuid=server_uuid)] self.stubs.Set(nova.compute.API, 'get_all', fake_get_all) - self.flags(allow_admin_api=False) req = fakes.HTTPRequest.blank('/v2/fake/servers?status=active') servers = self.controller.index(req)['servers'] @@ -925,8 +921,8 @@ class ServersControllerTest(test.TestCase): def test_get_servers_invalid_status(self): """Test getting servers by invalid status""" - self.flags(allow_admin_api=False) - req = fakes.HTTPRequest.blank('/v2/fake/servers?status=unknown') + req = fakes.HTTPRequest.blank('/v2/fake/servers?status=unknown', + use_admin_context=False) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.index, req) def test_get_servers_allows_name(self): @@ -939,7 +935,6 @@ class ServersControllerTest(test.TestCase): return [fakes.stub_instance(100, uuid=server_uuid)] self.stubs.Set(nova.compute.API, 'get_all', fake_get_all) - self.flags(allow_admin_api=False) req = fakes.HTTPRequest.blank('/v2/fake/servers?name=whee.*') servers = self.controller.index(req)['servers'] @@ -972,47 +967,11 @@ class ServersControllerTest(test.TestCase): req = fakes.HTTPRequest.blank('/v2/fake/servers?%s' % params) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.index, req) - def test_get_servers_unknown_or_admin_options1(self): - """Test getting servers by admin-only or unknown options. - This tests when admin_api is off. Make sure the admin and - unknown options are stripped before they get to - compute_api.get_all() + def test_get_servers_admin_filters_as_user(self): + """Test getting servers by admin-only or unknown options when + context is not admin. Make sure the admin and unknown options + are stripped before they get to compute_api.get_all() """ - - self.flags(allow_admin_api=False) - - server_uuid = str(utils.gen_uuid()) - - def fake_get_all(compute_self, context, search_opts=None): - self.assertNotEqual(search_opts, None) - # Allowed by user - self.assertTrue('name' in search_opts) - self.assertTrue('status' in search_opts) - # Allowed only by admins with admin API on - self.assertFalse('ip' in search_opts) - self.assertFalse('unknown_option' in search_opts) - return [fakes.stub_instance(100, uuid=server_uuid)] - - self.stubs.Set(nova.compute.API, 'get_all', fake_get_all) - - query_str = "name=foo&ip=10.*&status=active&unknown_option=meow" - req = fakes.HTTPRequest.blank('/v2/fake/servers?%s' % query_str, - use_admin_context=True) - res = self.controller.index(req) - - servers = res['servers'] - self.assertEqual(len(servers), 1) - self.assertEqual(servers[0]['id'], server_uuid) - - def test_get_servers_unknown_or_admin_options2(self): - """Test getting servers by admin-only or unknown options. - This tests when admin_api is on, but context is a user. - Make sure the admin and unknown options are stripped before - they get to compute_api.get_all() - """ - - self.flags(allow_admin_api=True) - server_uuid = str(utils.gen_uuid()) def fake_get_all(compute_self, context, search_opts=None): @@ -1035,14 +994,10 @@ class ServersControllerTest(test.TestCase): self.assertEqual(len(servers), 1) self.assertEqual(servers[0]['id'], server_uuid) - def test_get_servers_unknown_or_admin_options3(self): - """Test getting servers by admin-only or unknown options. - This tests when admin_api is on and context is admin. - All options should be passed through to compute_api.get_all() + def test_get_servers_admin_options_as_admin(self): + """Test getting servers by admin-only or unknown options when + context is admin. All options should be passed """ - - self.flags(allow_admin_api=True) - server_uuid = str(utils.gen_uuid()) def fake_get_all(compute_self, context, search_opts=None): @@ -1069,8 +1024,6 @@ class ServersControllerTest(test.TestCase): """Test getting servers by ip with admin_api enabled and admin context """ - self.flags(allow_admin_api=True) - server_uuid = str(utils.gen_uuid()) def fake_get_all(compute_self, context, search_opts=None): @@ -1092,8 +1045,6 @@ class ServersControllerTest(test.TestCase): """Test getting servers by ip6 with admin_api enabled and admin context """ - self.flags(allow_admin_api=True) - server_uuid = str(utils.gen_uuid()) def fake_get_all(compute_self, context, search_opts=None): diff --git a/nova/tests/policy.json b/nova/tests/policy.json index 807de6921..ff30cd43d 100644 --- a/nova/tests/policy.json +++ b/nova/tests/policy.json @@ -69,6 +69,38 @@ "compute:restore": [], + "compute_extension:accounts": [], + "compute_extension:admin_actions": [], + "compute_extension:cloudpipe": [], + "compute_extension:console_output": [], + "compute_extension:consoles": [], + "compute_extension:createserverext": [], + "compute_extension:deferred_delete": [], + "compute_extension:disk_config": [], + "compute_extension:extended_status": [], + "compute_extension:flavorextraspecs": [], + "compute_extension:floating_ip_dns": [], + "compute_extension:floating_ip_pools": [], + "compute_extension:floating_ips": [], + "compute_extension:hosts": [], + "compute_extension:keypairs": [], + "compute_extension:multinic": [], + "compute_extension:networks": [], + "compute_extension:quotas": [], + "compute_extension:rescue": [], + "compute_extension:security_groups": [], + "compute_extension:server_action_list": [], + "compute_extension:server_diagnostics": [], + "compute_extension:simple_tenant_usage": [], + "compute_extension:users": [], + "compute_extension:virtual_interfaces": [], + "compute_extension:virtual_storage_arrays": [], + "compute_extension:volumes": [], + "compute_extension:volumetypes": [], + "compute_extension:zones": [], + + + "volume:create": [], "volume:get": [], "volume:get_all": [], |
