diff options
| author | Sandy Walsh <sandy.walsh@rackspace.com> | 2011-01-03 15:46:55 -0800 |
|---|---|---|
| committer | Sandy Walsh <sandy.walsh@rackspace.com> | 2011-01-03 15:46:55 -0800 |
| commit | e43dd605ed6e19b4c3fb349461bf5aede16217b0 (patch) | |
| tree | e8bd18dca7dfc5c467e0d675615e66324c6b16b9 /nova/api | |
| parent | dd1e36b9690a2c2de18c565c496b25295a13d0aa (diff) | |
| parent | f4a2d86519434f934bd6c90ba401b08875420d19 (diff) | |
| download | nova-e43dd605ed6e19b4c3fb349461bf5aede16217b0.tar.gz nova-e43dd605ed6e19b4c3fb349461bf5aede16217b0.tar.xz nova-e43dd605ed6e19b4c3fb349461bf5aede16217b0.zip | |
First pass at feature parity. Includes Image ID hash
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/openstack/__init__.py | 6 | ||||
| -rw-r--r-- | nova/api/openstack/backup_schedules.py | 6 | ||||
| -rw-r--r-- | nova/api/openstack/common.py | 24 | ||||
| -rw-r--r-- | nova/api/openstack/images.py | 19 | ||||
| -rw-r--r-- | nova/api/openstack/servers.py | 27 | ||||
| -rw-r--r-- | nova/api/openstack/sharedipgroups.py | 10 |
6 files changed, 84 insertions, 8 deletions
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index a1430caed..0b54c7233 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -51,6 +51,10 @@ flags.DEFINE_string('os_api_ratelimiting', 'nova.api.openstack.ratelimiting.RateLimitingMiddleware', 'Default ratelimiting implementation for the Openstack API') +flags.DEFINE_string('os_krm_mapping_file', + 'krm_mapping.json', + 'Location of OpenStack Flavor/OS:EC2 Kernel/Ramdisk/Machine JSON file.') + flags.DEFINE_bool('allow_admin_api', False, 'When True, this API service will accept admin operations.') @@ -109,7 +113,7 @@ class APIRouter(wsgi.Router): collection={'detail': 'GET'}) mapper.resource("flavor", "flavors", controller=flavors.Controller(), collection={'detail': 'GET'}) - mapper.resource("sharedipgroup", "sharedipgroups", + mapper.resource("shared_ip_group", "shared_ip_groups", controller=sharedipgroups.Controller()) super(APIRouter, self).__init__(mapper) diff --git a/nova/api/openstack/backup_schedules.py b/nova/api/openstack/backup_schedules.py index fcc07bdd3..197125d86 100644 --- a/nova/api/openstack/backup_schedules.py +++ b/nova/api/openstack/backup_schedules.py @@ -15,7 +15,9 @@ # License for the specific language governing permissions and limitations # under the License. +import logging import time + from webob import exc from nova import wsgi @@ -46,8 +48,8 @@ class Controller(wsgi.Controller): 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.HTTPNotFound()) + return faults.Fault(exc.HTTPNotImplemented()) def delete(self, req, server_id, id): """ Deletes an existing backup schedule """ - return faults.Fault(exc.HTTPNotFound()) + return faults.Fault(exc.HTTPNotImplemented()) diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index ac0572c96..e2c7ed7ba 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -15,6 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. +from nova import exception + def limited(items, req): """Return a slice of items according to requested offset and limit. @@ -34,3 +36,25 @@ def limited(items, req): limit = min(1000, limit) range_end = offset + limit return items[offset:range_end] + + +def get_image_id_from_image_hash(image_service, context, image_hash): + """Given an Image ID Hash, return an objectstore Image ID. + + image_service - reference to objectstore compatible image service. + context - security context for image service requests. + image_hash - hash of the image ID. + """ + + # FIX(sandy): This is terribly inefficient. It pulls all images + # from objectstore in order to find the match. ObjectStore + # should have a numeric counterpart to the string ID. + try: + items = image_service.detail(context) + except NotImplementedError: + items = image_service.index(context) + for image in items: + image_id = image['imageId'] + if abs(hash(image_id)) == int(image_hash): + return image_id + raise exception.NotFound(image_hash) diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 867ee5a7e..4da3b943b 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -15,6 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. +import logging + from webob import exc from nova import flags @@ -27,6 +29,7 @@ from nova.api.openstack import common from nova.api.openstack import faults from nova.compute import api as compute_api + FLAGS = flags.FLAGS @@ -89,6 +92,12 @@ def _filter_keys(item, keys): return dict((k, v) for k, v in item.iteritems() if k in keys) +def _convert_image_id_to_hash(image): + image_id = abs(hash(image['imageId'])) + image['imageId'] = image_id + image['id'] = image_id + + class Controller(wsgi.Controller): _serialization_metadata = { @@ -113,6 +122,9 @@ class Controller(wsgi.Controller): items = self._service.detail(req.environ['nova.context']) except NotImplementedError: items = self._service.index(req.environ['nova.context']) + for image in items: + _convert_image_id_to_hash(image) + items = common.limited(items, req) items = [_translate_keys(item) for item in items] items = [_translate_status(item) for item in items] @@ -120,7 +132,12 @@ class Controller(wsgi.Controller): def show(self, req, id): """Return data about the given image id""" - return dict(image=self._service.show(req.environ['nova.context'], id)) + image_id = common.get_image_id_from_image_hash(self._service, + req.environ['nova.context'], id) + + image = self._service.show(req.environ['nova.context'], image_id) + _convert_image_id_to_hash(image) + return dict(image=image) def delete(self, req, id): # Only public images are supported for now. diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index c5cbe21ef..35c3324ab 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -15,13 +15,16 @@ # License for the specific language governing permissions and limitations # under the License. +import json import logging import traceback from webob import exc from nova import exception +from nova import flags from nova import wsgi +from nova import utils from nova.api.openstack import common from nova.api.openstack import faults from nova.auth import manager as auth_manager @@ -35,6 +38,9 @@ LOG = logging.getLogger('server') LOG.setLevel(logging.DEBUG) +FLAGS = flags.FLAGS + + def _translate_detail_keys(inst): """ Coerces into dictionary format, mapping everything to Rackspace-like attributes for return""" @@ -81,6 +87,7 @@ class Controller(wsgi.Controller): def __init__(self): self.compute_api = compute_api.ComputeAPI() + self._image_service = utils.import_object(FLAGS.image_service) super(Controller, self).__init__() def index(self, req): @@ -120,6 +127,18 @@ class Controller(wsgi.Controller): return faults.Fault(exc.HTTPNotFound()) return exc.HTTPAccepted() + def _get_kernel_ramdisk_from_image(self, image_id): + mapping_filename = FLAGS.os_krm_mapping_file + + with open(mapping_filename) as f: + mapping = json.load(f) + if mapping.has_key(image_id): + return mapping[image_id] + + raise exception.NotFound( + _("No entry for image '%s' in mapping file '%s'") % + (image_id, mapping_filename)) + def create(self, req): """ Creates a new server for a given user """ env = self._deserialize(req.body, req) @@ -128,10 +147,15 @@ class Controller(wsgi.Controller): key_pair = auth_manager.AuthManager.get_key_pairs( req.environ['nova.context'])[0] + image_id = common.get_image_id_from_image_hash(self._image_service, + req.environ['nova.context'], env['server']['imageId']) + kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image(image_id) instances = self.compute_api.create_instances( req.environ['nova.context'], instance_types.get_by_flavor_id(env['server']['flavorId']), - env['server']['imageId'], + image_id, + kernel_id = kernel_id, + ramdisk_id = ramdisk_id, display_name=env['server']['name'], description=env['server']['name'], key_name=key_pair['name'], @@ -163,6 +187,7 @@ class Controller(wsgi.Controller): """ Multi-purpose method used to reboot, rebuild, and resize a server """ input_dict = self._deserialize(req.body, req) + #TODO(sandy): rebuild/resize not supported. try: reboot_type = input_dict['reboot']['type'] except Exception: diff --git a/nova/api/openstack/sharedipgroups.py b/nova/api/openstack/sharedipgroups.py index 845f5bead..65595c8ff 100644 --- a/nova/api/openstack/sharedipgroups.py +++ b/nova/api/openstack/sharedipgroups.py @@ -15,6 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. +import logging + from webob import exc from nova import wsgi @@ -29,7 +31,7 @@ def _translate_keys(inst): def _translate_detail_keys(inst): """ Coerces a shared IP group instance into proper dictionary format with correctly mapped attributes """ - return dict(sharedIpGroup=inst) + return dict(sharedIpGroups=inst) class Controller(wsgi.Controller): @@ -46,6 +48,8 @@ class Controller(wsgi.Controller): def show(self, req, id): """ Shows in-depth information on a specific Shared IP Group """ + if id == 'detail': + return _translate_detail_keys({}) return _translate_keys({}) def update(self, req, id): @@ -54,7 +58,7 @@ class Controller(wsgi.Controller): def delete(self, req, id): """ Deletes a Shared IP Group """ - raise faults.Fault(exc.HTTPNotFound()) + raise faults.Fault(exc.HTTPNotImplemented()) def detail(self, req, id): """ Returns a complete list of Shared IP Groups """ @@ -62,4 +66,4 @@ class Controller(wsgi.Controller): def create(self, req): """ Creates a new Shared IP group """ - raise faults.Fault(exc.HTTPNotFound()) + raise faults.Fault(exc.HTTPNotImplemented()) |
