From 6797c5acc47fb5111ef821d6b074cb635692a9fb Mon Sep 17 00:00:00 2001 From: Monsyne Dragon Date: Thu, 3 Mar 2011 15:41:45 +0000 Subject: Add in multi-tenant support in openstack api. --- nova/api/openstack/__init__.py | 25 +++++++++ nova/api/openstack/accounts.py | 73 ++++++++++++++++++++++++++ nova/api/openstack/auth.py | 54 +++++++++++++++++--- nova/api/openstack/backup_schedules.py | 6 +-- nova/api/openstack/consoles.py | 10 ++-- nova/api/openstack/flavors.py | 6 +-- nova/api/openstack/images.py | 12 ++--- nova/api/openstack/servers.py | 38 +++++++------- nova/api/openstack/shared_ip_groups.py | 12 ++--- nova/api/openstack/users.py | 93 ++++++++++++++++++++++++++++++++++ nova/api/openstack/zones.py | 12 ++--- 11 files changed, 286 insertions(+), 55 deletions(-) create mode 100644 nova/api/openstack/accounts.py create mode 100644 nova/api/openstack/users.py (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index b1b38ed2d..73d52192e 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -27,6 +27,7 @@ import webob.exc from nova import flags from nova import log as logging from nova import wsgi +from nova.api.openstack import accounts from nova.api.openstack import faults from nova.api.openstack import backup_schedules from nova.api.openstack import consoles @@ -34,6 +35,7 @@ from nova.api.openstack import flavors from nova.api.openstack import images from nova.api.openstack import servers from nova.api.openstack import shared_ip_groups +from nova.api.openstack import users from nova.api.openstack import zones @@ -71,6 +73,18 @@ class APIRouter(wsgi.Router): def __init__(self): mapper = routes.Mapper() + accounts_controller = accounts.Controller() + mapper.connect("account", "/{id}", + controller=accounts_controller, action="show", + conditions=dict(method=["GET"])) + if FLAGS.allow_admin_api: + mapper.connect("/{id}", + controller=accounts_controller, action="update", + conditions=dict(method=["PUT"])) + mapper.connect("/{id}", + controller=accounts_controller, action="delete", + conditions=dict(method=["DELETE"])) + server_members = {'action': 'POST'} if FLAGS.allow_admin_api: LOG.debug(_("Including admin operations in API.")) @@ -84,27 +98,38 @@ class APIRouter(wsgi.Router): server_members['inject_network_info'] = 'POST' mapper.resource("zone", "zones", controller=zones.Controller(), + path_prefix="{account_id}/", + collection={'detail': 'GET'}) + + mapper.resource("user", "users", controller=users.Controller(), + path_prefix="{account_id}/", collection={'detail': 'GET'}) mapper.resource("server", "servers", controller=servers.Controller(), collection={'detail': 'GET'}, + path_prefix="{account_id}/", member=server_members) mapper.resource("backup_schedule", "backup_schedule", controller=backup_schedules.Controller(), + path_prefix="{account_id}/servers/{server_id}/", parent_resource=dict(member_name='server', collection_name='servers')) mapper.resource("console", "consoles", controller=consoles.Controller(), + path_prefix="{account_id}/servers/{server_id}/", parent_resource=dict(member_name='server', collection_name='servers')) mapper.resource("image", "images", controller=images.Controller(), + path_prefix="{account_id}/", collection={'detail': 'GET'}) mapper.resource("flavor", "flavors", controller=flavors.Controller(), + path_prefix="{account_id}/", collection={'detail': 'GET'}) mapper.resource("shared_ip_group", "shared_ip_groups", + path_prefix="{account_id}/", collection={'detail': 'GET'}, controller=shared_ip_groups.Controller()) diff --git a/nova/api/openstack/accounts.py b/nova/api/openstack/accounts.py new file mode 100644 index 000000000..264fdab99 --- /dev/null +++ b/nova/api/openstack/accounts.py @@ -0,0 +1,73 @@ +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import common + +from nova import exception +from nova import flags +from nova import log as logging +from nova import wsgi + +from nova.auth import manager + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.api.openstack') + + +def _translate_keys(account): + return dict(id=account.id, + name=account.name, + description=account.description, + manager=account.project_manager_id) + + +class Controller(wsgi.Controller): + + _serialization_metadata = { + 'application/xml': { + "attributes": { + "account": ["id", "name", "description", "manager"]}}} + + 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.NotAuthorized("Not admin user.") + + def show(self, req, id): + """Return data about the given account id""" + account = self.manager.get_project(id) + return dict(account=_translate_keys(account)) + + def delete(self, req, id): + self._check_admin(req.environ['nova.context']) + self.manager.delete_project(id) + return {} + + def update(self, req, id): + """ This is really create or update. """ + self._check_admin(req.environ['nova.context']) + env = self._deserialize(req.body, req) + description = env['account'].get('description') + manager = env['account'].get('manager') + try: + account = self.manager.get_project(id) + self.manager.modify_project(id, manager, description) + except exception.NotFound: + account = self.manager.create_project(id, manager, description) + return dict(account=_translate_keys(account)) diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index 6011e6115..e77910fed 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -28,11 +28,13 @@ from nova import context from nova import db from nova import exception from nova import flags +from nova import log as logging from nova import manager from nova import utils from nova import wsgi from nova.api.openstack import faults +LOG = logging.getLogger('nova.api.openstack') FLAGS = flags.FLAGS @@ -50,14 +52,27 @@ class AuthMiddleware(wsgi.Middleware): def __call__(self, req): if not self.has_authentication(req): return self.authenticate(req) - user = self.get_user_by_authentication(req) + account_name = req.path_info_peek() if not user: return faults.Fault(webob.exc.HTTPUnauthorized()) - project = self.auth.get_project(FLAGS.default_project) - req.environ['nova.context'] = context.RequestContext(user, project) + if not account_name: + if self.auth.is_admin(user): + account_name = FLAGS.default_project + else: + return faults.Fault(webob.exc.HTTPUnauthorized()) + try: + account = self.auth.get_project(account_name) + except exception.NotFound: + return faults.Fault(webob.exc.HTTPUnauthorized()) + + if not self.auth.is_admin(user) and \ + not self.auth.is_project_member(user, account): + return faults.Fault(webob.exc.HTTPUnauthorized()) + + req.environ['nova.context'] = context.RequestContext(user, account) return self.application def has_authentication(self, req): @@ -70,6 +85,7 @@ class AuthMiddleware(wsgi.Middleware): # Unless the request is explicitly made against // don't # honor it path_info = req.path_info + account_name = None if len(path_info) > 1: return faults.Fault(webob.exc.HTTPUnauthorized()) @@ -79,7 +95,10 @@ class AuthMiddleware(wsgi.Middleware): except KeyError: return faults.Fault(webob.exc.HTTPUnauthorized()) - token, user = self._authorize_user(username, key, req) + if ':' in username: + account_name, username = username.rsplit(':', 1) + + token, user = self._authorize_user(username, account_name, key, req) if user and token: res = webob.Response() res.headers['X-Auth-Token'] = token.token_hash @@ -116,23 +135,44 @@ class AuthMiddleware(wsgi.Middleware): return self.auth.get_user(token.user_id) return None - def _authorize_user(self, username, key, req): + def _authorize_user(self, username, account_name, key, req): """Generates a new token and assigns it to a user. username - string + account_name - string key - string API key req - webob.Request object """ ctxt = context.get_admin_context() user = self.auth.get_user_from_access_key(key) + if account_name: + try: + account = self.auth.get_project(account_name) + except exception.NotFound: + return None, None + else: + # (dragondm) punt and try to determine account. + # this is something of a hack, but a user on 1 account is a + # common case, and is the way the current RS code works. + accounts = self.auth.get_projects(user=user) + if len(accounts) == 1: + account = accounts[0] + else: + #we can't tell what account they are logging in for. + return None, None + if user and user.name == username: token_hash = hashlib.sha1('%s%s%f' % (username, key, time.time())).hexdigest() token_dict = {} token_dict['token_hash'] = token_hash token_dict['cdn_management_url'] = '' - # Same as auth url, e.g. http://foo.org:8774/baz/v1.0 - token_dict['server_management_url'] = req.url + # auth url + project (account) id, e.g. + # http://foo.org:8774/baz/v1.0/myacct/ + os_url = '%s%s%s/' % (req.url, + '' if req.url.endswith('/') else '/', + account.id) + token_dict['server_management_url'] = os_url token_dict['storage_url'] = '' token_dict['user_id'] = user.id token = self.db.auth_token_create(ctxt, token_dict) diff --git a/nova/api/openstack/backup_schedules.py b/nova/api/openstack/backup_schedules.py index 7abb5f884..a4d5939df 100644 --- a/nova/api/openstack/backup_schedules.py +++ b/nova/api/openstack/backup_schedules.py @@ -40,15 +40,15 @@ class Controller(wsgi.Controller): def __init__(self): pass - def index(self, req, server_id): + def index(self, req, server_id, **kw): """ Returns the list of backup schedules for a given instance """ return _translate_keys({}) - def create(self, req, server_id): + def create(self, req, server_id, **kw): """ No actual update method required, since the existing API allows both create and update through a POST """ return faults.Fault(exc.HTTPNotImplemented()) - def delete(self, req, server_id, id): + def delete(self, req, server_id, id, **kw): """ Deletes an existing backup schedule """ return faults.Fault(exc.HTTPNotImplemented()) diff --git a/nova/api/openstack/consoles.py b/nova/api/openstack/consoles.py index 9ebdbe710..85b2a4140 100644 --- a/nova/api/openstack/consoles.py +++ b/nova/api/openstack/consoles.py @@ -55,7 +55,7 @@ class Controller(wsgi.Controller): self.console_api = console.API() super(Controller, self).__init__() - def index(self, req, server_id): + def index(self, req, server_id, **kw): """Returns a list of consoles for this instance""" consoles = self.console_api.get_consoles( req.environ['nova.context'], @@ -63,14 +63,14 @@ class Controller(wsgi.Controller): return dict(consoles=[_translate_keys(console) for console in consoles]) - def create(self, req, server_id): + def create(self, req, server_id, **kw): """Creates a new console""" #info = self._deserialize(req.body, req) self.console_api.create_console( req.environ['nova.context'], int(server_id)) - def show(self, req, server_id, id): + def show(self, req, server_id, id, **kw): """Shows in-depth information on a specific console""" try: console = self.console_api.get_console( @@ -81,11 +81,11 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPNotFound()) return _translate_detail_keys(console) - def update(self, req, server_id, id): + def update(self, req, server_id, id, **kw): """You can't update a console""" raise faults.Fault(exc.HTTPNotImplemented()) - def delete(self, req, server_id, id): + def delete(self, req, server_id, id, **kw): """Deletes a console""" try: self.console_api.delete_console(req.environ['nova.context'], diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index f620d4107..79c3e1ab3 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -32,18 +32,18 @@ class Controller(wsgi.Controller): "attributes": { "flavor": ["id", "name", "ram", "disk"]}}} - def index(self, req): + def index(self, req, **kw): """Return all flavors in brief.""" return dict(flavors=[dict(id=flavor['id'], name=flavor['name']) for flavor in self.detail(req)['flavors']]) - def detail(self, req): + def detail(self, req, **kw): """Return all flavors in detail.""" items = [self.show(req, id)['flavor'] for id in self._all_ids()] items = common.limited(items, req) return dict(flavors=items) - def show(self, req, id): + def show(self, req, id, **kw): """Return data about the given flavor id.""" for name, val in instance_types.INSTANCE_TYPES.iteritems(): if val['flavorid'] == int(id): diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index cf85a496f..5bc5b9978 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -115,14 +115,14 @@ class Controller(wsgi.Controller): def __init__(self): self._service = utils.import_object(FLAGS.image_service) - def index(self, req): + def index(self, req, **kw): """Return all public images in brief""" items = self._service.index(req.environ['nova.context']) items = common.limited(items, req) items = [_filter_keys(item, ('id', 'name')) for item in items] return dict(images=items) - def detail(self, req): + def detail(self, req, **kw): """Return all public images in detail""" try: items = self._service.detail(req.environ['nova.context']) @@ -136,7 +136,7 @@ class Controller(wsgi.Controller): items = [_translate_status(item) for item in items] return dict(images=items) - def show(self, req, id): + def show(self, req, id, **kw): """Return data about the given image id""" image_id = common.get_image_id_from_image_hash(self._service, req.environ['nova.context'], id) @@ -145,11 +145,11 @@ class Controller(wsgi.Controller): _convert_image_id_to_hash(image) return dict(image=image) - def delete(self, req, id): + def delete(self, req, id, **kw): # Only public images are supported for now. raise faults.Fault(exc.HTTPNotFound()) - def create(self, req): + def create(self, req, **kw): context = req.environ['nova.context'] env = self._deserialize(req.body, req) instance_id = env["image"]["serverId"] @@ -160,7 +160,7 @@ class Controller(wsgi.Controller): return dict(image=image_meta) - def update(self, req, id): + def update(self, req, id, **kw): # Users may not modify public images, and that's all that # we support for now. raise faults.Fault(exc.HTTPNotFound()) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 69273ad7b..426de92be 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -105,11 +105,11 @@ class Controller(wsgi.Controller): self._image_service = utils.import_object(FLAGS.image_service) super(Controller, self).__init__() - def index(self, req): + def index(self, req, **kw): """ Returns a list of server names and ids for a given user """ return self._items(req, entity_maker=_translate_keys) - def detail(self, req): + def detail(self, req, **kw): """ Returns a list of server details for a given user """ return self._items(req, entity_maker=_translate_detail_keys) @@ -123,7 +123,7 @@ class Controller(wsgi.Controller): res = [entity_maker(inst)['server'] for inst in limited_list] return dict(servers=res) - def show(self, req, id): + def show(self, req, id, **kw): """ Returns server details by server id """ try: instance = self.compute_api.get(req.environ['nova.context'], id) @@ -131,7 +131,7 @@ class Controller(wsgi.Controller): except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - def delete(self, req, id): + def delete(self, req, id, **kw): """ Destroys a server """ try: self.compute_api.delete(req.environ['nova.context'], id) @@ -139,7 +139,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPNotFound()) return exc.HTTPAccepted() - def create(self, req): + def create(self, req, **kw): """ Creates a new server for a given user """ env = self._deserialize(req.body, req) if not env: @@ -180,7 +180,7 @@ class Controller(wsgi.Controller): onset_files=env.get('onset_files', [])) return _translate_keys(instances[0]) - def update(self, req, id): + def update(self, req, id, **kw): """ Updates the server name or password """ inst_dict = self._deserialize(req.body, req) if not inst_dict: @@ -202,7 +202,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPNotFound()) return exc.HTTPNoContent() - def action(self, req, id): + def action(self, req, id, **kw): """ Multi-purpose method used to reboot, rebuild, and resize a server """ input_dict = self._deserialize(req.body, req) @@ -219,7 +219,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def lock(self, req, id): + def lock(self, req, id, **kw): """ lock the instance with id admin only operation @@ -234,7 +234,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def unlock(self, req, id): + def unlock(self, req, id, **kw): """ unlock the instance with id admin only operation @@ -249,7 +249,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def get_lock(self, req, id): + def get_lock(self, req, id, **kw): """ return the boolean state of (instance with id)'s lock @@ -263,7 +263,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def reset_network(self, req, id): + def reset_network(self, req, id, **kw): """ Reset networking on an instance (admin only). @@ -277,7 +277,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def inject_network_info(self, req, id): + def inject_network_info(self, req, id, **kw): """ Inject network info for an instance (admin only). @@ -291,7 +291,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def pause(self, req, id): + def pause(self, req, id, **kw): """ Permit Admins to Pause the server. """ ctxt = req.environ['nova.context'] try: @@ -302,7 +302,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def unpause(self, req, id): + def unpause(self, req, id, **kw): """ Permit Admins to Unpause the server. """ ctxt = req.environ['nova.context'] try: @@ -313,7 +313,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def suspend(self, req, id): + def suspend(self, req, id, **kw): """permit admins to suspend the server""" context = req.environ['nova.context'] try: @@ -324,7 +324,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def resume(self, req, id): + def resume(self, req, id, **kw): """permit admins to resume the server from suspend""" context = req.environ['nova.context'] try: @@ -335,7 +335,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def get_ajax_console(self, req, id): + def get_ajax_console(self, req, id, **kw): """ Returns a url to an instance's ajaxterm console. """ try: self.compute_api.get_ajax_console(req.environ['nova.context'], @@ -344,12 +344,12 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPNotFound()) return exc.HTTPAccepted() - def diagnostics(self, req, id): + def diagnostics(self, req, id, **kw): """Permit Admins to retrieve server diagnostics.""" ctxt = req.environ["nova.context"] return self.compute_api.get_diagnostics(ctxt, id) - def actions(self, req, id): + def actions(self, req, id, **kw): """Permit Admins to retrieve server actions.""" ctxt = req.environ["nova.context"] items = self.compute_api.get_actions(ctxt, id) diff --git a/nova/api/openstack/shared_ip_groups.py b/nova/api/openstack/shared_ip_groups.py index 5d78f9377..e3c917749 100644 --- a/nova/api/openstack/shared_ip_groups.py +++ b/nova/api/openstack/shared_ip_groups.py @@ -40,26 +40,26 @@ class Controller(wsgi.Controller): 'attributes': { 'sharedIpGroup': []}}} - def index(self, req): + def index(self, req, **kw): """ Returns a list of Shared IP Groups for the user """ return dict(sharedIpGroups=[]) - def show(self, req, id): + def show(self, req, id, **kw): """ Shows in-depth information on a specific Shared IP Group """ return _translate_keys({}) - def update(self, req, id): + def update(self, req, id, **kw): """ You can't update a Shared IP Group """ raise faults.Fault(exc.HTTPNotImplemented()) - def delete(self, req, id): + def delete(self, req, id, **kw): """ Deletes a Shared IP Group """ raise faults.Fault(exc.HTTPNotImplemented()) - def detail(self, req): + def detail(self, req, **kw): """ Returns a complete list of Shared IP Groups """ return _translate_detail_keys({}) - def create(self, req): + def create(self, req, **kw): """ Creates a new Shared IP group """ raise faults.Fault(exc.HTTPNotImplemented()) diff --git a/nova/api/openstack/users.py b/nova/api/openstack/users.py new file mode 100644 index 000000000..c0b7544f9 --- /dev/null +++ b/nova/api/openstack/users.py @@ -0,0 +1,93 @@ +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import common + +from nova import exception +from nova import flags +from nova import log as logging +from nova import wsgi + +from nova.auth import manager + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.api.openstack') + + +def _translate_keys(user): + return dict(id=user.id, + name=user.name, + access=user.access, + secret=user.secret, + admin=user.admin) + + +class Controller(wsgi.Controller): + + _serialization_metadata = { + 'application/xml': { + "attributes": { + "user": ["id", "name", "access", "secret", "admin"]}}} + + 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.NotAuthorized("Not admin user") + + def index(self, req, **kw): + """Return all users in brief""" + users = self.manager.get_users() + users = common.limited(users, req) + users = [_translate_keys(user) for user in users] + return dict(users=users) + + def detail(self, req, **kw): + """Return all users in detail""" + return self.index(req) + + def show(self, req, id, **kw): + """Return data about the given user id""" + user = self.manager.get_user(id) + return dict(user=_translate_keys(user)) + + def delete(self, req, id, **kw): + self._check_admin(req.environ['nova.context']) + self.manager.delete_user(id) + return {} + + def create(self, req, **kw): + self._check_admin(req.environ['nova.context']) + env = self._deserialize(req.body, req) + is_admin = env['user'].get('admin') in ('T', 'True', True) + name = env['user'].get('name') + access = env['user'].get('access') + secret = env['user'].get('secret') + user = self.manager.create_user(name, access, secret, is_admin) + return dict(user=_translate_keys(user)) + + def update(self, req, id, **kw): + self._check_admin(req.environ['nova.context']) + env = self._deserialize(req.body, req) + is_admin = env['user'].get('admin') + if is_admin is not None: + is_admin = is_admin in ('T', 'True', True) + access = env['user'].get('access') + secret = env['user'].get('secret') + self.manager.modify_user(id, access, secret, is_admin) + return dict(user=_translate_keys(self.manager.get_user(id))) diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py index d5206da20..30bf2b67b 100644 --- a/nova/api/openstack/zones.py +++ b/nova/api/openstack/zones.py @@ -43,35 +43,35 @@ class Controller(wsgi.Controller): "attributes": { "zone": ["id", "api_url"]}}} - def index(self, req): + def index(self, req, **kw): """Return all zones in brief""" items = db.zone_get_all(req.environ['nova.context']) items = common.limited(items, req) items = [_scrub_zone(item) for item in items] return dict(zones=items) - def detail(self, req): + def detail(self, req, **kw): """Return all zones in detail""" return self.index(req) - def show(self, req, id): + def show(self, req, id, **kw): """Return data about the given zone id""" zone_id = int(id) zone = db.zone_get(req.environ['nova.context'], zone_id) return dict(zone=_scrub_zone(zone)) - def delete(self, req, id): + def delete(self, req, id, **kw): zone_id = int(id) db.zone_delete(req.environ['nova.context'], zone_id) return {} - def create(self, req): + def create(self, req, **kw): context = req.environ['nova.context'] env = self._deserialize(req.body, req) zone = db.zone_create(context, env["zone"]) return dict(zone=_scrub_zone(zone)) - def update(self, req, id): + def update(self, req, id, **kw): context = req.environ['nova.context'] env = self._deserialize(req.body, req) zone_id = int(id) -- cgit From 417f6ca5c54878a6bea4d545126f93ecb6a043b4 Mon Sep 17 00:00:00 2001 From: Monsyne Dragon Date: Thu, 3 Mar 2011 22:22:00 +0000 Subject: localize a few error messages. --- nova/api/openstack/accounts.py | 2 +- nova/api/openstack/users.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/accounts.py b/nova/api/openstack/accounts.py index 264fdab99..3b90d2776 100644 --- a/nova/api/openstack/accounts.py +++ b/nova/api/openstack/accounts.py @@ -47,7 +47,7 @@ class Controller(wsgi.Controller): """ 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.NotAuthorized("Not admin user.") + raise exception.NotAuthorized(_("Not admin user.")) def show(self, req, id): """Return data about the given account id""" diff --git a/nova/api/openstack/users.py b/nova/api/openstack/users.py index c0b7544f9..ae3bf7791 100644 --- a/nova/api/openstack/users.py +++ b/nova/api/openstack/users.py @@ -48,7 +48,7 @@ class Controller(wsgi.Controller): """ 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.NotAuthorized("Not admin user") + raise exception.NotAuthorized(_("Not admin user")) def index(self, req, **kw): """Return all users in brief""" -- cgit From c5bfab9a0d213cee549371f05e74747cfcd8f998 Mon Sep 17 00:00:00 2001 From: Ryan Lane Date: Thu, 3 Mar 2011 23:05:00 +0000 Subject: Changing output of status from showing the user as the owner, to showing the project --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index b1917e9ea..cadda97db 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -562,7 +562,7 @@ class CloudController(object): if context.is_admin: v['status'] = '%s (%s, %s, %s, %s)' % ( volume['status'], - volume['user_id'], + volume['project_id'], volume['host'], instance_data, volume['mountpoint']) -- cgit From cbc2956a4e863c1bc952c7cef6045c39d293818d Mon Sep 17 00:00:00 2001 From: Monsyne Dragon Date: Tue, 8 Mar 2011 17:18:13 +0000 Subject: Remove addition of account to service url. --- nova/api/openstack/__init__.py | 24 ++++------------------ nova/api/openstack/auth.py | 46 +++++++++--------------------------------- 2 files changed, 13 insertions(+), 57 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 005d330a6..a655b1c85 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -73,18 +73,6 @@ class APIRouter(wsgi.Router): def __init__(self): mapper = routes.Mapper() - accounts_controller = accounts.Controller() - mapper.connect("account", "/{id}", - controller=accounts_controller, action="show", - conditions=dict(method=["GET"])) - if FLAGS.allow_admin_api: - mapper.connect("/{id}", - controller=accounts_controller, action="update", - conditions=dict(method=["PUT"])) - mapper.connect("/{id}", - controller=accounts_controller, action="delete", - conditions=dict(method=["DELETE"])) - server_members = {'action': 'POST'} if FLAGS.allow_admin_api: LOG.debug(_("Including admin operations in API.")) @@ -101,38 +89,34 @@ class APIRouter(wsgi.Router): server_members['inject_network_info'] = 'POST' mapper.resource("zone", "zones", controller=zones.Controller(), - path_prefix="{account_id}/", collection={'detail': 'GET'}) mapper.resource("user", "users", controller=users.Controller(), - path_prefix="{account_id}/", collection={'detail': 'GET'}) + mapper.resource("account", "accounts", + controller=accounts.Controller(), + collection={'detail': 'GET'}) + mapper.resource("server", "servers", controller=servers.Controller(), collection={'detail': 'GET'}, - path_prefix="{account_id}/", member=server_members) mapper.resource("backup_schedule", "backup_schedule", controller=backup_schedules.Controller(), - path_prefix="{account_id}/servers/{server_id}/", parent_resource=dict(member_name='server', collection_name='servers')) mapper.resource("console", "consoles", controller=consoles.Controller(), - path_prefix="{account_id}/servers/{server_id}/", parent_resource=dict(member_name='server', collection_name='servers')) mapper.resource("image", "images", controller=images.Controller(), - path_prefix="{account_id}/", collection={'detail': 'GET'}) mapper.resource("flavor", "flavors", controller=flavors.Controller(), - path_prefix="{account_id}/", collection={'detail': 'GET'}) mapper.resource("shared_ip_group", "shared_ip_groups", - path_prefix="{account_id}/", collection={'detail': 'GET'}, controller=shared_ip_groups.Controller()) diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index e77910fed..e71fc69e3 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -53,19 +53,15 @@ class AuthMiddleware(wsgi.Middleware): if not self.has_authentication(req): return self.authenticate(req) user = self.get_user_by_authentication(req) - account_name = req.path_info_peek() - + accounts = self.auth.get_projects(user=user) if not user: return faults.Fault(webob.exc.HTTPUnauthorized()) - if not account_name: - if self.auth.is_admin(user): - account_name = FLAGS.default_project - else: - return faults.Fault(webob.exc.HTTPUnauthorized()) - try: - account = self.auth.get_project(account_name) - except exception.NotFound: + if accounts: + #we are punting on this til auth is settled, + #and possibly til api v1.1 (mdragon) + account = accounts[0] + else: return faults.Fault(webob.exc.HTTPUnauthorized()) if not self.auth.is_admin(user) and \ @@ -85,7 +81,6 @@ class AuthMiddleware(wsgi.Middleware): # Unless the request is explicitly made against // don't # honor it path_info = req.path_info - account_name = None if len(path_info) > 1: return faults.Fault(webob.exc.HTTPUnauthorized()) @@ -95,10 +90,7 @@ class AuthMiddleware(wsgi.Middleware): except KeyError: return faults.Fault(webob.exc.HTTPUnauthorized()) - if ':' in username: - account_name, username = username.rsplit(':', 1) - - token, user = self._authorize_user(username, account_name, key, req) + token, user = self._authorize_user(username, key, req) if user and token: res = webob.Response() res.headers['X-Auth-Token'] = token.token_hash @@ -135,31 +127,15 @@ class AuthMiddleware(wsgi.Middleware): return self.auth.get_user(token.user_id) return None - def _authorize_user(self, username, account_name, key, req): + def _authorize_user(self, username, key, req): """Generates a new token and assigns it to a user. username - string - account_name - string key - string API key req - webob.Request object """ ctxt = context.get_admin_context() user = self.auth.get_user_from_access_key(key) - if account_name: - try: - account = self.auth.get_project(account_name) - except exception.NotFound: - return None, None - else: - # (dragondm) punt and try to determine account. - # this is something of a hack, but a user on 1 account is a - # common case, and is the way the current RS code works. - accounts = self.auth.get_projects(user=user) - if len(accounts) == 1: - account = accounts[0] - else: - #we can't tell what account they are logging in for. - return None, None if user and user.name == username: token_hash = hashlib.sha1('%s%s%f' % (username, key, @@ -167,11 +143,7 @@ class AuthMiddleware(wsgi.Middleware): token_dict = {} token_dict['token_hash'] = token_hash token_dict['cdn_management_url'] = '' - # auth url + project (account) id, e.g. - # http://foo.org:8774/baz/v1.0/myacct/ - os_url = '%s%s%s/' % (req.url, - '' if req.url.endswith('/') else '/', - account.id) + os_url = req.url token_dict['server_management_url'] = os_url token_dict['storage_url'] = '' token_dict['user_id'] = user.id -- cgit From 429fdb1ee733a62052c67f4e42c62447fc716ec0 Mon Sep 17 00:00:00 2001 From: Monsyne Dragon Date: Wed, 9 Mar 2011 18:10:45 +0000 Subject: removed uneeded **kw args leftover from removed account-in-url changes. --- nova/api/openstack/backup_schedules.py | 6 ++--- nova/api/openstack/consoles.py | 10 ++++---- nova/api/openstack/flavors.py | 6 ++--- nova/api/openstack/images.py | 12 +++++----- nova/api/openstack/servers.py | 42 +++++++++++++++++----------------- nova/api/openstack/shared_ip_groups.py | 12 +++++----- nova/api/openstack/users.py | 12 +++++----- nova/api/openstack/zones.py | 12 +++++----- 8 files changed, 56 insertions(+), 56 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/backup_schedules.py b/nova/api/openstack/backup_schedules.py index a4d5939df..7abb5f884 100644 --- a/nova/api/openstack/backup_schedules.py +++ b/nova/api/openstack/backup_schedules.py @@ -40,15 +40,15 @@ class Controller(wsgi.Controller): def __init__(self): pass - def index(self, req, server_id, **kw): + def index(self, req, server_id): """ Returns the list of backup schedules for a given instance """ return _translate_keys({}) - def create(self, req, server_id, **kw): + def create(self, req, server_id): """ No actual update method required, since the existing API allows both create and update through a POST """ return faults.Fault(exc.HTTPNotImplemented()) - def delete(self, req, server_id, id, **kw): + def delete(self, req, server_id, id): """ Deletes an existing backup schedule """ return faults.Fault(exc.HTTPNotImplemented()) diff --git a/nova/api/openstack/consoles.py b/nova/api/openstack/consoles.py index 85b2a4140..9ebdbe710 100644 --- a/nova/api/openstack/consoles.py +++ b/nova/api/openstack/consoles.py @@ -55,7 +55,7 @@ class Controller(wsgi.Controller): self.console_api = console.API() super(Controller, self).__init__() - def index(self, req, server_id, **kw): + def index(self, req, server_id): """Returns a list of consoles for this instance""" consoles = self.console_api.get_consoles( req.environ['nova.context'], @@ -63,14 +63,14 @@ class Controller(wsgi.Controller): return dict(consoles=[_translate_keys(console) for console in consoles]) - def create(self, req, server_id, **kw): + def create(self, req, server_id): """Creates a new console""" #info = self._deserialize(req.body, req) self.console_api.create_console( req.environ['nova.context'], int(server_id)) - def show(self, req, server_id, id, **kw): + def show(self, req, server_id, id): """Shows in-depth information on a specific console""" try: console = self.console_api.get_console( @@ -81,11 +81,11 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPNotFound()) return _translate_detail_keys(console) - def update(self, req, server_id, id, **kw): + def update(self, req, server_id, id): """You can't update a console""" raise faults.Fault(exc.HTTPNotImplemented()) - def delete(self, req, server_id, id, **kw): + def delete(self, req, server_id, id): """Deletes a console""" try: self.console_api.delete_console(req.environ['nova.context'], diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index 1de67328b..f3d040ba3 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -34,17 +34,17 @@ class Controller(wsgi.Controller): "attributes": { "flavor": ["id", "name", "ram", "disk"]}}} - def index(self, req, **kw): + def index(self, req): """Return all flavors in brief.""" return dict(flavors=[dict(id=flavor['id'], name=flavor['name']) for flavor in self.detail(req)['flavors']]) - def detail(self, req, **kw): + def detail(self, req): """Return all flavors in detail.""" items = [self.show(req, id)['flavor'] for id in self._all_ids(req)] return dict(flavors=items) - def show(self, req, id, **kw): + def show(self, req, id): """Return data about the given flavor id.""" ctxt = req.environ['nova.context'] values = db.instance_type_get_by_flavor_id(ctxt, id) diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 5bc5b9978..cf85a496f 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -115,14 +115,14 @@ class Controller(wsgi.Controller): def __init__(self): self._service = utils.import_object(FLAGS.image_service) - def index(self, req, **kw): + def index(self, req): """Return all public images in brief""" items = self._service.index(req.environ['nova.context']) items = common.limited(items, req) items = [_filter_keys(item, ('id', 'name')) for item in items] return dict(images=items) - def detail(self, req, **kw): + def detail(self, req): """Return all public images in detail""" try: items = self._service.detail(req.environ['nova.context']) @@ -136,7 +136,7 @@ class Controller(wsgi.Controller): items = [_translate_status(item) for item in items] return dict(images=items) - def show(self, req, id, **kw): + def show(self, req, id): """Return data about the given image id""" image_id = common.get_image_id_from_image_hash(self._service, req.environ['nova.context'], id) @@ -145,11 +145,11 @@ class Controller(wsgi.Controller): _convert_image_id_to_hash(image) return dict(image=image) - def delete(self, req, id, **kw): + def delete(self, req, id): # Only public images are supported for now. raise faults.Fault(exc.HTTPNotFound()) - def create(self, req, **kw): + def create(self, req): context = req.environ['nova.context'] env = self._deserialize(req.body, req) instance_id = env["image"]["serverId"] @@ -160,7 +160,7 @@ class Controller(wsgi.Controller): return dict(image=image_meta) - def update(self, req, id, **kw): + def update(self, req, id): # Users may not modify public images, and that's all that # we support for now. raise faults.Fault(exc.HTTPNotFound()) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 54060c2bb..c2bf42b72 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -105,11 +105,11 @@ class Controller(wsgi.Controller): self._image_service = utils.import_object(FLAGS.image_service) super(Controller, self).__init__() - def index(self, req, **kw): + def index(self, req): """ Returns a list of server names and ids for a given user """ return self._items(req, entity_maker=_translate_keys) - def detail(self, req, **kw): + def detail(self, req): """ Returns a list of server details for a given user """ return self._items(req, entity_maker=_translate_detail_keys) @@ -123,7 +123,7 @@ class Controller(wsgi.Controller): res = [entity_maker(inst)['server'] for inst in limited_list] return dict(servers=res) - def show(self, req, id, **kw): + def show(self, req, id): """ Returns server details by server id """ try: instance = self.compute_api.get(req.environ['nova.context'], id) @@ -131,7 +131,7 @@ class Controller(wsgi.Controller): except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - def delete(self, req, id, **kw): + def delete(self, req, id): """ Destroys a server """ try: self.compute_api.delete(req.environ['nova.context'], id) @@ -139,7 +139,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPNotFound()) return exc.HTTPAccepted() - def create(self, req, **kw): + def create(self, req): """ Creates a new server for a given user """ env = self._deserialize(req.body, req) if not env: @@ -180,7 +180,7 @@ class Controller(wsgi.Controller): onset_files=env.get('onset_files', [])) return _translate_keys(instances[0]) - def update(self, req, id, **kw): + def update(self, req, id): """ Updates the server name or password """ inst_dict = self._deserialize(req.body, req) if not inst_dict: @@ -202,7 +202,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPNotFound()) return exc.HTTPNoContent() - def action(self, req, id, **kw): + def action(self, req, id): """Multi-purpose method used to reboot, rebuild, or resize a server""" @@ -267,7 +267,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def lock(self, req, id, **kw): + def lock(self, req, id): """ lock the instance with id admin only operation @@ -282,7 +282,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def unlock(self, req, id, **kw): + def unlock(self, req, id): """ unlock the instance with id admin only operation @@ -297,7 +297,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def get_lock(self, req, id, **kw): + def get_lock(self, req, id): """ return the boolean state of (instance with id)'s lock @@ -311,7 +311,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def reset_network(self, req, id, **kw): + def reset_network(self, req, id): """ Reset networking on an instance (admin only). @@ -325,7 +325,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def inject_network_info(self, req, id, **kw): + def inject_network_info(self, req, id): """ Inject network info for an instance (admin only). @@ -339,7 +339,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def pause(self, req, id, **kw): + def pause(self, req, id): """ Permit Admins to Pause the server. """ ctxt = req.environ['nova.context'] try: @@ -350,7 +350,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def unpause(self, req, id, **kw): + def unpause(self, req, id): """ Permit Admins to Unpause the server. """ ctxt = req.environ['nova.context'] try: @@ -361,7 +361,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def suspend(self, req, id, **kw): + def suspend(self, req, id): """permit admins to suspend the server""" context = req.environ['nova.context'] try: @@ -372,7 +372,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def resume(self, req, id, **kw): + def resume(self, req, id): """permit admins to resume the server from suspend""" context = req.environ['nova.context'] try: @@ -383,7 +383,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def rescue(self, req, id, **kw): + def rescue(self, req, id): """Permit users to rescue the server.""" context = req.environ["nova.context"] try: @@ -394,7 +394,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def unrescue(self, req, id, **kw): + def unrescue(self, req, id): """Permit users to unrescue the server.""" context = req.environ["nova.context"] try: @@ -405,7 +405,7 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() - def get_ajax_console(self, req, id, **kw): + def get_ajax_console(self, req, id): """ Returns a url to an instance's ajaxterm console. """ try: self.compute_api.get_ajax_console(req.environ['nova.context'], @@ -414,12 +414,12 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPNotFound()) return exc.HTTPAccepted() - def diagnostics(self, req, id, **kw): + def diagnostics(self, req, id): """Permit Admins to retrieve server diagnostics.""" ctxt = req.environ["nova.context"] return self.compute_api.get_diagnostics(ctxt, id) - def actions(self, req, id, **kw): + def actions(self, req, id): """Permit Admins to retrieve server actions.""" ctxt = req.environ["nova.context"] items = self.compute_api.get_actions(ctxt, id) diff --git a/nova/api/openstack/shared_ip_groups.py b/nova/api/openstack/shared_ip_groups.py index e3c917749..5d78f9377 100644 --- a/nova/api/openstack/shared_ip_groups.py +++ b/nova/api/openstack/shared_ip_groups.py @@ -40,26 +40,26 @@ class Controller(wsgi.Controller): 'attributes': { 'sharedIpGroup': []}}} - def index(self, req, **kw): + def index(self, req): """ Returns a list of Shared IP Groups for the user """ return dict(sharedIpGroups=[]) - def show(self, req, id, **kw): + def show(self, req, id): """ Shows in-depth information on a specific Shared IP Group """ return _translate_keys({}) - def update(self, req, id, **kw): + def update(self, req, id): """ You can't update a Shared IP Group """ raise faults.Fault(exc.HTTPNotImplemented()) - def delete(self, req, id, **kw): + def delete(self, req, id): """ Deletes a Shared IP Group """ raise faults.Fault(exc.HTTPNotImplemented()) - def detail(self, req, **kw): + def detail(self, req): """ Returns a complete list of Shared IP Groups """ return _translate_detail_keys({}) - def create(self, req, **kw): + def create(self, req): """ Creates a new Shared IP group """ raise faults.Fault(exc.HTTPNotImplemented()) diff --git a/nova/api/openstack/users.py b/nova/api/openstack/users.py index ae3bf7791..83ebec964 100644 --- a/nova/api/openstack/users.py +++ b/nova/api/openstack/users.py @@ -50,28 +50,28 @@ class Controller(wsgi.Controller): if not context.is_admin: raise exception.NotAuthorized(_("Not admin user")) - def index(self, req, **kw): + def index(self, req): """Return all users in brief""" users = self.manager.get_users() users = common.limited(users, req) users = [_translate_keys(user) for user in users] return dict(users=users) - def detail(self, req, **kw): + def detail(self, req): """Return all users in detail""" return self.index(req) - def show(self, req, id, **kw): + def show(self, req, id): """Return data about the given user id""" user = self.manager.get_user(id) return dict(user=_translate_keys(user)) - def delete(self, req, id, **kw): + def delete(self, req, id): self._check_admin(req.environ['nova.context']) self.manager.delete_user(id) return {} - def create(self, req, **kw): + def create(self, req): self._check_admin(req.environ['nova.context']) env = self._deserialize(req.body, req) is_admin = env['user'].get('admin') in ('T', 'True', True) @@ -81,7 +81,7 @@ class Controller(wsgi.Controller): user = self.manager.create_user(name, access, secret, is_admin) return dict(user=_translate_keys(user)) - def update(self, req, id, **kw): + def update(self, req, id): self._check_admin(req.environ['nova.context']) env = self._deserialize(req.body, req) is_admin = env['user'].get('admin') diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py index 30bf2b67b..d5206da20 100644 --- a/nova/api/openstack/zones.py +++ b/nova/api/openstack/zones.py @@ -43,35 +43,35 @@ class Controller(wsgi.Controller): "attributes": { "zone": ["id", "api_url"]}}} - def index(self, req, **kw): + def index(self, req): """Return all zones in brief""" items = db.zone_get_all(req.environ['nova.context']) items = common.limited(items, req) items = [_scrub_zone(item) for item in items] return dict(zones=items) - def detail(self, req, **kw): + def detail(self, req): """Return all zones in detail""" return self.index(req) - def show(self, req, id, **kw): + def show(self, req, id): """Return data about the given zone id""" zone_id = int(id) zone = db.zone_get(req.environ['nova.context'], zone_id) return dict(zone=_scrub_zone(zone)) - def delete(self, req, id, **kw): + def delete(self, req, id): zone_id = int(id) db.zone_delete(req.environ['nova.context'], zone_id) return {} - def create(self, req, **kw): + def create(self, req): context = req.environ['nova.context'] env = self._deserialize(req.body, req) zone = db.zone_create(context, env["zone"]) return dict(zone=_scrub_zone(zone)) - def update(self, req, id, **kw): + def update(self, req, id): context = req.environ['nova.context'] env = self._deserialize(req.body, req) zone_id = int(id) -- cgit From e76aad24ce8a9b1b7de1b2f874c22c9995f3071f Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Thu, 10 Mar 2011 14:30:17 +0100 Subject: Only include ramdisk and kernel id if they are actually set. --- nova/api/ec2/cloud.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index b1917e9ea..1d2254225 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -147,8 +147,6 @@ class CloudController(object): instance_ref['id']) ec2_id = ec2utils.id_to_ec2_id(instance_ref['id']) image_ec2_id = self._image_ec2_id(instance_ref['image_id'], 'machine') - k_ec2_id = self._image_ec2_id(instance_ref['kernel_id'], 'kernel') - r_ec2_id = self._image_ec2_id(instance_ref['ramdisk_id'], 'ramdisk') data = { 'user-data': base64.b64decode(instance_ref['user_data']), 'meta-data': { @@ -167,8 +165,6 @@ class CloudController(object): 'instance-type': instance_ref['instance_type'], 'local-hostname': hostname, 'local-ipv4': address, - 'kernel-id': k_ec2_id, - 'ramdisk-id': r_ec2_id, 'placement': {'availability-zone': availability_zone}, 'public-hostname': hostname, 'public-ipv4': floating_ip or '', @@ -176,6 +172,13 @@ class CloudController(object): 'reservation-id': instance_ref['reservation_id'], 'security-groups': '', 'mpi': mpi}} + + for image_type in ['kernel', 'ramdisk']: + if '%s_id' % image_type in instance_ref: + ec2_id = self._image_ec2_id(instance_ref['%s_id' % image_type], + image_type) + data['meta-data']['%s-id' % image_type] = ec2_id + if False: # TODO(vish): store ancestor ids data['ancestor-ami-ids'] = [] if False: # TODO(vish): store product codes -- cgit From be66b329d5b94ffbfb782355ef342eadbaed72a5 Mon Sep 17 00:00:00 2001 From: Monsyne Dragon Date: Thu, 10 Mar 2011 22:14:53 +0000 Subject: Fix a fer nits jaypipes found in review. --- nova/api/openstack/accounts.py | 18 +++++++++++++++--- nova/api/openstack/users.py | 4 ++-- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/accounts.py b/nova/api/openstack/accounts.py index 3b90d2776..dd88c3390 100644 --- a/nova/api/openstack/accounts.py +++ b/nova/api/openstack/accounts.py @@ -21,6 +21,7 @@ from nova import log as logging from nova import wsgi from nova.auth import manager +from nova.api.openstack import faults FLAGS = flags.FLAGS LOG = logging.getLogger('nova.api.openstack') @@ -44,11 +45,17 @@ class Controller(wsgi.Controller): 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 """ + """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.NotAuthorized(_("Not admin user.")) + def index(self, req): + raise faults.Fault(exc.HTTPNotImplemented()) + + def detail(self, req): + raise faults.Fault(exc.HTTPNotImplemented()) + def show(self, req, id): """Return data about the given account id""" account = self.manager.get_project(id) @@ -59,8 +66,13 @@ class Controller(wsgi.Controller): self.manager.delete_project(id) return {} + def create(self, req): + """We use update with create-or-update semantics + because the id comes from an external source""" + raise faults.Fault(exc.HTTPNotImplemented()) + def update(self, req, id): - """ This is really create or update. """ + """This is really create or update.""" self._check_admin(req.environ['nova.context']) env = self._deserialize(req.body, req) description = env['account'].get('description') diff --git a/nova/api/openstack/users.py b/nova/api/openstack/users.py index 83ebec964..5bb20a718 100644 --- a/nova/api/openstack/users.py +++ b/nova/api/openstack/users.py @@ -45,8 +45,8 @@ class Controller(wsgi.Controller): 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 """ + """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.NotAuthorized(_("Not admin user")) -- cgit