From 3b70003d932607ccc13fe4cd9381475035603a70 Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Tue, 24 Aug 2010 17:03:03 -0400 Subject: Flavors work --- nova/api/rackspace/flavors.py | 34 +++++++++++++++++++++++- nova/api/rackspace/images.py | 62 ++++--------------------------------------- 2 files changed, 38 insertions(+), 58 deletions(-) diff --git a/nova/api/rackspace/flavors.py b/nova/api/rackspace/flavors.py index 986f11434..8c5ffa438 100644 --- a/nova/api/rackspace/flavors.py +++ b/nova/api/rackspace/flavors.py @@ -15,4 +15,36 @@ # License for the specific language governing permissions and limitations # under the License. -class Controller(object): pass +from nova.api.rackspace import base +from nova.api.rackspace import _id_translator +from nova import flavor +from webob import exc + +class Controller(base.Controller): + + _serialization_metadata = { + 'application/xml': { + "attributes": { + "flavor": [ "id", "name", "ram", "disk" ] + } + } + } + + def __init__(self): + self._service = flavor.service.FlavorService.load() + self._id_translator = self._id_translator.RackspaceAPIIdTranslator( + "flavor", self._service.__class__.__name__) + + def index(self, req): + """Return all flavors.""" + items = self._service.index() + for flavor in items: + flavor['id'] = self._id_translator.to_rs_id(flavor['id']) + return dict(flavors=items) + + def show(self, req, id): + """Return data about the given flavor id.""" + opaque_id = self._id_translator.from_rs_id(id) + item = self._service.show(opaque_id) + item['id'] = id + return dict(flavor=item) diff --git a/nova/api/rackspace/images.py b/nova/api/rackspace/images.py index 36a26688c..09f55ea96 100644 --- a/nova/api/rackspace/images.py +++ b/nova/api/rackspace/images.py @@ -15,8 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. -from nova import datastore from nova.api.rackspace import base +from nova.api.rackspace import _id_translator from nova.api.services import image from webob import exc @@ -33,34 +33,19 @@ class Controller(base.Controller): def __init__(self): self._service = image.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._id_translator = _id_translator.RackspaceAPIIdTranslator( + "image", self._service.__class__.__name__) def index(self, req): """Return all public images.""" 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 +63,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) -- cgit From 0828326898e3bc219c8205e27a3cc942e2790934 Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Wed, 25 Aug 2010 16:27:01 -0400 Subject: Use compute.instance_types for flavor data instead of a FlavorService --- nova/api/rackspace/flavors.py | 27 +++++++++++++-------------- nova/compute/instance_types.py | 14 +++++++------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/nova/api/rackspace/flavors.py b/nova/api/rackspace/flavors.py index 8c5ffa438..59981f1c5 100644 --- a/nova/api/rackspace/flavors.py +++ b/nova/api/rackspace/flavors.py @@ -16,11 +16,11 @@ # under the License. from nova.api.rackspace import base -from nova.api.rackspace import _id_translator -from nova import flavor +from nova.compute import instance_types from webob import exc class Controller(base.Controller): + """Flavor controller for the Rackspace API.""" _serialization_metadata = { 'application/xml': { @@ -30,21 +30,20 @@ class Controller(base.Controller): } } - def __init__(self): - self._service = flavor.service.FlavorService.load() - self._id_translator = self._id_translator.RackspaceAPIIdTranslator( - "flavor", self._service.__class__.__name__) - def index(self, req): """Return all flavors.""" - items = self._service.index() - for flavor in items: - flavor['id'] = self._id_translator.to_rs_id(flavor['id']) + 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.""" - opaque_id = self._id_translator.from_rs_id(id) - item = self._service.show(opaque_id) - item['id'] = id - return dict(flavor=item) + 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/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)} -- cgit From cf0b5de1f78fd81ada2bada8c84e26b3238b8596 Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Wed, 25 Aug 2010 16:46:53 -0400 Subject: Turn imageid translator into general translator for rackspace api ids --- nova/api/rackspace/_id_translator.py | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 nova/api/rackspace/_id_translator.py 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) -- cgit From c9d3b7c3ae71bbbe6f3077dcee13be41a14a6733 Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Wed, 25 Aug 2010 17:48:08 -0400 Subject: Support GET //detail --- nova/api/rackspace/__init__.py | 6 ++++-- nova/api/rackspace/flavors.py | 7 ++++++- nova/api/rackspace/images.py | 11 ++++++++--- nova/image/__init__.py | 0 4 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 nova/image/__init__.py 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/flavors.py b/nova/api/rackspace/flavors.py index 59981f1c5..60b35c939 100644 --- a/nova/api/rackspace/flavors.py +++ b/nova/api/rackspace/flavors.py @@ -31,7 +31,12 @@ class Controller(base.Controller): } def index(self, req): - """Return all flavors.""" + """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) diff --git a/nova/api/rackspace/images.py b/nova/api/rackspace/images.py index 06fb0d38f..2f3e928b9 100644 --- a/nova/api/rackspace/images.py +++ b/nova/api/rackspace/images.py @@ -15,7 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. -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 @@ -32,12 +32,17 @@ class Controller(base.Controller): } def __init__(self): - self._service = image.ImageService.load() + 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._id_translator.to_rs_id(img['id']) diff --git a/nova/image/__init__.py b/nova/image/__init__.py new file mode 100644 index 000000000..e69de29bb -- cgit