summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Gundlach <michael.gundlach@rackspace.com>2010-08-30 16:03:22 +0000
committerTarmac <>2010-08-30 16:03:22 +0000
commitca37c1aba4fd83652c68094c74d22c27ee094e99 (patch)
tree6948dd954abb6edc92579d5b1d26a217b7a1c773
parent5f14a7955b9ef90afed91bda0343130d83e15a73 (diff)
parentc9d3b7c3ae71bbbe6f3077dcee13be41a14a6733 (diff)
downloadnova-ca37c1aba4fd83652c68094c74d22c27ee094e99.tar.gz
nova-ca37c1aba4fd83652c68094c74d22c27ee094e99.tar.xz
nova-ca37c1aba4fd83652c68094c74d22c27ee094e99.zip
Add Flavors controller supporting
GET /flavors GET /flavors/detail GET /flavors/<id> Also add GET /images/detail Turn the RackspaceAPIImageIdTranslator into a RackspaceAPIIdTranslator, so that it can be used to translate IDs for other rackspace API components as well (servers, backup schedules.) I thought I'd need it for flavors but it turns out flavors are so simple I could hard code their ids into compute.instance_types.INSTANCE_TYPES.
-rw-r--r--nova/api/rackspace/__init__.py6
-rw-r--r--nova/api/rackspace/_id_translator.py42
-rw-r--r--nova/api/rackspace/flavors.py38
-rw-r--r--nova/api/rackspace/images.py73
-rw-r--r--nova/compute/instance_types.py14
-rw-r--r--nova/image/__init__.py0
6 files changed, 103 insertions, 70 deletions
diff --git a/nova/api/rackspace/__init__.py b/nova/api/rackspace/__init__.py
index 27e78f801..b4d666d63 100644
--- a/nova/api/rackspace/__init__.py
+++ b/nova/api/rackspace/__init__.py
@@ -74,8 +74,10 @@ class APIRouter(wsgi.Router):
def __init__(self):
mapper = routes.Mapper()
mapper.resource("server", "servers", controller=servers.Controller())
- mapper.resource("image", "images", controller=images.Controller())
- mapper.resource("flavor", "flavors", controller=flavors.Controller())
+ mapper.resource("image", "images", controller=images.Controller(),
+ collection={'detail': 'GET'})
+ mapper.resource("flavor", "flavors", controller=flavors.Controller(),
+ collection={'detail': 'GET'})
mapper.resource("sharedipgroup", "sharedipgroups",
controller=sharedipgroups.Controller())
super(APIRouter, self).__init__(mapper)
diff --git a/nova/api/rackspace/_id_translator.py b/nova/api/rackspace/_id_translator.py
new file mode 100644
index 000000000..aec5fb6a5
--- /dev/null
+++ b/nova/api/rackspace/_id_translator.py
@@ -0,0 +1,42 @@
+from nova import datastore
+
+class RackspaceAPIIdTranslator(object):
+ """
+ Converts Rackspace API ids to and from the id format for a given
+ strategy.
+ """
+
+ def __init__(self, id_type, service_name):
+ """
+ Creates a translator for ids of the given type (e.g. 'flavor'), for the
+ given storage service backend class name (e.g. 'LocalFlavorService').
+ """
+
+ self._store = datastore.Redis.instance()
+ key_prefix = "rsapi.idtranslator.%s.%s" % (id_type, service_name)
+ # Forward (strategy format -> RS format) and reverse translation keys
+ self._fwd_key = "%s.fwd" % key_prefix
+ self._rev_key = "%s.rev" % key_prefix
+
+ def to_rs_id(self, opaque_id):
+ """Convert an id from a strategy-specific one to a Rackspace one."""
+ result = self._store.hget(self._fwd_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" % self._fwd_key)
+ if self._store.hsetnx(self._fwd_key, str(opaque_id), nextid):
+ # If someone else didn't beat us to it, store the reverse
+ # mapping as well.
+ self._store.hset(self._rev_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(self._fwd_key, str(opaque_id)))
+
+ def from_rs_id(self, strategy_name, rs_id):
+ """Convert a Rackspace id to a strategy-specific one."""
+ return self._store.hget(self._rev_key, rs_id)
diff --git a/nova/api/rackspace/flavors.py b/nova/api/rackspace/flavors.py
index 986f11434..60b35c939 100644
--- a/nova/api/rackspace/flavors.py
+++ b/nova/api/rackspace/flavors.py
@@ -15,4 +15,40 @@
# License for the specific language governing permissions and limitations
# under the License.
-class Controller(object): pass
+from nova.api.rackspace import base
+from nova.compute import instance_types
+from webob import exc
+
+class Controller(base.Controller):
+ """Flavor controller for the Rackspace API."""
+
+ _serialization_metadata = {
+ 'application/xml': {
+ "attributes": {
+ "flavor": [ "id", "name", "ram", "disk" ]
+ }
+ }
+ }
+
+ 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):
+ """Return all flavors in detail."""
+ items = [self.show(req, id)['flavor'] for id in self._all_ids()]
+ return dict(flavors=items)
+
+ def show(self, req, id):
+ """Return data about the given flavor id."""
+ for name, val in instance_types.INSTANCE_TYPES.iteritems():
+ if val['flavorid'] == int(id):
+ item = dict(ram=val['memory_mb'], disk=val['local_gb'],
+ id=val['flavorid'], name=name)
+ return dict(flavor=item)
+ raise exc.HTTPNotFound()
+
+ def _all_ids(self):
+ """Return the list of all flavorids."""
+ return [i['flavorid'] for i in instance_types.INSTANCE_TYPES.values()]
diff --git a/nova/api/rackspace/images.py b/nova/api/rackspace/images.py
index 370980fe9..2f3e928b9 100644
--- a/nova/api/rackspace/images.py
+++ b/nova/api/rackspace/images.py
@@ -15,9 +15,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from nova import datastore
-from nova import image
+import nova.image.service
from nova.api.rackspace import base
+from nova.api.rackspace import _id_translator
from webob import exc
class Controller(base.Controller):
@@ -32,35 +32,25 @@ class Controller(base.Controller):
}
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)
+ self._service = nova.image.service.ImageService.load()
+ self._id_translator = _id_translator.RackspaceAPIIdTranslator(
+ "image", self._service.__class__.__name__)
def index(self, req):
- """Return all public images."""
+ """Return all public images in brief."""
+ return dict(images=[dict(id=img['id'], name=img['name'])
+ for img in self.detail(req)['images']])
+
+ def detail(self, req):
+ """Return all public images in detail."""
data = self._service.index()
for img in data:
- img['id'] = self._to_rs_id(img['id'])
+ img['id'] = self._id_translator.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)
+ opaque_id = self._id_translator.from_rs_id(id)
img = self._service.show(opaque_id)
img['id'] = id
return dict(image=img)
@@ -78,40 +68,3 @@ class Controller(base.Controller):
# 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/compute/instance_types.py b/nova/compute/instance_types.py
index 439be3c7d..0102bae54 100644
--- a/nova/compute/instance_types.py
+++ b/nova/compute/instance_types.py
@@ -21,10 +21,10 @@
The built-in instance properties.
"""
-INSTANCE_TYPES = {}
-INSTANCE_TYPES['m1.tiny'] = {'memory_mb': 512, 'vcpus': 1, 'local_gb': 0}
-INSTANCE_TYPES['m1.small'] = {'memory_mb': 1024, 'vcpus': 1, 'local_gb': 10}
-INSTANCE_TYPES['m1.medium'] = {'memory_mb': 2048, 'vcpus': 2, 'local_gb': 10}
-INSTANCE_TYPES['m1.large'] = {'memory_mb': 4096, 'vcpus': 4, 'local_gb': 10}
-INSTANCE_TYPES['m1.xlarge'] = {'memory_mb': 8192, 'vcpus': 4, 'local_gb': 10}
-INSTANCE_TYPES['c1.medium'] = {'memory_mb': 2048, 'vcpus': 4, 'local_gb': 10}
+INSTANCE_TYPES = {
+ 'm1.tiny': dict(memory_mb=512, vcpus=1, local_gb=0, flavorid=1),
+ 'm1.small': dict(memory_mb=1024, vcpus=1, local_gb=10, flavorid=2),
+ 'm1.medium': dict(memory_mb=2048, vcpus=2, local_gb=10, flavorid=3),
+ 'm1.large': dict(memory_mb=4096, vcpus=4, local_gb=10, flavorid=4),
+ 'm1.xlarge': dict(memory_mb=8192, vcpus=4, local_gb=10, flavorid=5),
+ 'c1.medium': dict(memory_mb=2048, vcpus=4, local_gb=10, flavorid=6)}
diff --git a/nova/image/__init__.py b/nova/image/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/nova/image/__init__.py