Remove admin_only ext attr in favor of authz
Working on blueprint separate-nova-adminapi. This removes the admin_only extension attribute and the allow_admin_api flag. The approach we're going for now is to load all extensions, but to set an admin-only rule in our policy file for those extensions that should be limited to just admin users. Now that all of our admin api code has been moved to extensions, in order to prevent admin api code from being loaded, simply remove it from the extension list. Change-Id: Ic574e06af44922ba764013b769077fc5099fd1a2
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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": [],
|
||||
|
||||
@@ -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.')
|
||||
|
||||
@@ -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.')
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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']
|
||||
if authorize(context):
|
||||
# Attach our slave template to the response object
|
||||
resp_obj.attach(xml=ExtendedStatusesTemplate())
|
||||
|
||||
# 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
|
||||
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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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']
|
||||
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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-'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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": [],
|
||||
|
||||
Reference in New Issue
Block a user