diff options
| author | Michael Gundlach <michael.gundlach@rackspace.com> | 2010-08-25 17:52:52 +0000 |
|---|---|---|
| committer | Tarmac <> | 2010-08-25 17:52:52 +0000 |
| commit | 686ad09fe4416bb578661a42f6f083528d4a7ca9 (patch) | |
| tree | b879c74a111b500d112023e1610a9bd0b24bbb73 /nova/api | |
| parent | 90ca9b373935f2e2bddedf1f33befb35f89aaab4 (diff) | |
| parent | 428b3256ad7e47e9f389ac8ce0ff70cc3d720e9e (diff) | |
| download | nova-686ad09fe4416bb578661a42f6f083528d4a7ca9.tar.gz nova-686ad09fe4416bb578661a42f6f083528d4a7ca9.tar.xz nova-686ad09fe4416bb578661a42f6f083528d4a7ca9.zip | |
Initial support for Rackspace API /image requests. They will eventually be backed by Glance.
Because we don't expect Glance to support non-public images for the Austin release, all we support is index() and show().
The WSGI controller uses a service to interact with the image store (the "ImageService"). Eventually it will use a GlanceImageService, but since Glance isn't implemented yet it's hard coded to use a LocalImageService for testing.
The ImageService maps URIs to image data (because Glance will be the canonical backend and that's how Glance does it), but the Rackspace API maps ids to image data. So the images.Controller stores a mapping in the global Redis service to convert from URIs to ids.
Courtesy of whatthecommit.com:
(\ /)
(O.o)
(> <) Bunny approves these changes.
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/rackspace/images.py | 101 | ||||
| -rw-r--r-- | nova/api/rackspace/notes.txt | 23 |
2 files changed, 123 insertions, 1 deletions
diff --git a/nova/api/rackspace/images.py b/nova/api/rackspace/images.py index 986f11434..370980fe9 100644 --- a/nova/api/rackspace/images.py +++ b/nova/api/rackspace/images.py @@ -15,4 +15,103 @@ # License for the specific language governing permissions and limitations # under the License. -class Controller(object): pass +from nova import datastore +from nova import image +from nova.api.rackspace import base +from webob import exc + +class Controller(base.Controller): + + _serialization_metadata = { + 'application/xml': { + "attributes": { + "image": [ "id", "name", "updated", "created", "status", + "serverId", "progress" ] + } + } + } + + def __init__(self): + self._service = image.service.ImageService.load() + self._id_translator = RackspaceAPIImageIdTranslator() + + def _to_rs_id(self, image_id): + """ + Convert an image id from the format of our ImageService strategy + to the Rackspace API format (an int). + """ + strategy = self._service.__class__.__name__ + return self._id_translator.to_rs_id(strategy, image_id) + + def _from_rs_id(self, rs_image_id): + """ + Convert an image id from the Rackspace API format (an int) to the + format of our ImageService strategy. + """ + strategy = self._service.__class__.__name__ + return self._id_translator.from_rs_id(strategy, rs_image_id) + + def index(self, req): + """Return all public images.""" + data = self._service.index() + for img in data: + img['id'] = self._to_rs_id(img['id']) + return dict(images=data) + + def show(self, req, id): + """Return data about the given image id.""" + opaque_id = self._from_rs_id(id) + img = self._service.show(opaque_id) + img['id'] = id + return dict(image=img) + + def delete(self, req, id): + # Only public images are supported for now. + raise exc.HTTPNotFound() + + def create(self, req): + # Only public images are supported for now, so a request to + # make a backup of a server cannot be supproted. + raise exc.HTTPNotFound() + + def update(self, req, id): + # Users may not modify public images, and that's all that + # we support for now. + raise exc.HTTPNotFound() + + +class RackspaceAPIImageIdTranslator(object): + """ + Converts Rackspace API image ids to and from the id format for a given + strategy. + """ + + def __init__(self): + self._store = datastore.Redis.instance() + self._key_template = "rsapi.idstrategies.image.%s.%s" + + def to_rs_id(self, strategy_name, opaque_id): + """Convert an id from a strategy-specific one to a Rackspace one.""" + key = self._key_template % (strategy_name, "fwd") + result = self._store.hget(key, str(opaque_id)) + if result: # we have a mapping from opaque to RS for this strategy + return int(result) + else: + # Store the mapping. + nextid = self._store.incr("%s.lastid" % key) + if self._store.hsetnx(key, str(opaque_id), nextid): + # If someone else didn't beat us to it, store the reverse + # mapping as well. + key = self._key_template % (strategy_name, "rev") + self._store.hset(key, nextid, str(opaque_id)) + return nextid + else: + # Someone beat us to it; use their number instead, and + # discard nextid (which is OK -- we don't require that + # every int id be used.) + return int(self._store.hget(key, str(opaque_id))) + + def from_rs_id(self, strategy_name, rs_id): + """Convert a Rackspace id to a strategy-specific one.""" + key = self._key_template % (strategy_name, "rev") + return self._store.hget(key, rs_id) diff --git a/nova/api/rackspace/notes.txt b/nova/api/rackspace/notes.txt new file mode 100644 index 000000000..e133bf5ea --- /dev/null +++ b/nova/api/rackspace/notes.txt @@ -0,0 +1,23 @@ +We will need: + +ImageService +a service that can do crud on image information. not user-specific. opaque +image ids. + +GlanceImageService(ImageService): +image ids are URIs. + +LocalImageService(ImageService): +image ids are random strings. + +RackspaceAPITranslationStore: +translates RS server/images/flavor/etc ids into formats required +by a given ImageService strategy. + +api.rackspace.images.Controller: +uses an ImageService strategy behind the scenes to do its fetching; it just +converts int image id into a strategy-specific image id. + +who maintains the mapping from user to [images he owns]? nobody, because +we have no way of enforcing access to his images, without kryptex which +won't be in Austin. |
