From 0ef621d47eeea421820a2191de53dee9e83d8c44 Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Fri, 1 Oct 2010 16:06:14 -0400 Subject: Adds BaseImageService and flag to control image service loading. Adds unit test for local image service. --- nova/api/rackspace/images.py | 7 +- nova/flags.py | 4 ++ nova/image/service.py | 114 ++++++++++++++++++++++++++++---- nova/tests/api/rackspace/test_images.py | 102 +++++++++++++++++++++++++--- 4 files changed, 206 insertions(+), 21 deletions(-) diff --git a/nova/api/rackspace/images.py b/nova/api/rackspace/images.py index 4a7dd489c..d4ab8ce3c 100644 --- a/nova/api/rackspace/images.py +++ b/nova/api/rackspace/images.py @@ -17,12 +17,17 @@ from webob import exc +from nova import flags +from nova import utils from nova import wsgi from nova.api.rackspace import _id_translator import nova.api.rackspace import nova.image.service from nova.api.rackspace import faults + +FLAGS = flags.FLAGS + class Controller(wsgi.Controller): _serialization_metadata = { @@ -35,7 +40,7 @@ class Controller(wsgi.Controller): } def __init__(self): - self._service = nova.image.service.ImageService.load() + self._service = utils.import_object(FLAGS.image_service) self._id_translator = _id_translator.RackspaceAPIIdTranslator( "image", self._service.__class__.__name__) diff --git a/nova/flags.py b/nova/flags.py index c32cdd7a4..ab80e83fb 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -222,6 +222,10 @@ DEFINE_string('volume_manager', 'nova.volume.manager.AOEManager', DEFINE_string('scheduler_manager', 'nova.scheduler.manager.SchedulerManager', 'Manager for scheduler') +# The service to use for image search and retrieval +DEFINE_string('image_service', 'nova.image.service.LocalImageService', + 'The service to use for retrieving and searching for images.') + DEFINE_string('host', socket.gethostname(), 'name of this node') diff --git a/nova/image/service.py b/nova/image/service.py index 1a7a258b7..4bceab6ee 100644 --- a/nova/image/service.py +++ b/nova/image/service.py @@ -20,34 +20,117 @@ import os.path import random import string -class ImageService(object): - """Provides storage and retrieval of disk image objects.""" +from nova import utils +from nova import flags - @staticmethod - def load(): - """Factory method to return image service.""" - #TODO(gundlach): read from config. - class_ = LocalImageService - return class_() + +FLAGS = flags.FLAGS + + +flags.DEFINE_string('glance_teller_address', '127.0.0.1', + 'IP address or URL where Glance\'s Teller service resides') +flags.DEFINE_string('glance_teller_port', '9191', + 'Port for Glance\'s Teller service') +flags.DEFINE_string('glance_parallax_address', '127.0.0.1', + 'IP address or URL where Glance\'s Parallax service resides') +flags.DEFINE_string('glance_parallax_port', '9191', + 'Port for Glance\'s Parallax service') + + +class BaseImageService(object): + + """Base class for providing image search and retrieval services""" def index(self): """ Return a dict from opaque image id to image data. """ + raise NotImplementedError def show(self, id): """ Returns a dict containing image data for the given opaque image id. """ + raise NotImplementedError + + def create(self, data): + """ + Store the image data and return the new image id. + + :raises AlreadyExists if the image already exist. + """ + raise NotImplementedError + + def update(self, image_id, data): + """Replace the contents of the given image with the new data. -class GlanceImageService(ImageService): + :raises NotFound if the image does not exist. + + """ + raise NotImplementedError + + def delete(self, image_id): + """ + Delete the given image. + + :raises NotFound if the image does not exist. + + """ + raise NotImplementedError + + +class GlanceImageService(BaseImageService): + """Provides storage and retrieval of disk image objects within Glance.""" - # TODO(gundlach): once Glance has an API, build this. - pass + def index(self): + """ + Calls out to Parallax for a list of images available + """ + raise NotImplementedError + + def show(self, id): + """ + Returns a dict containing image data for the given opaque image id. + """ + raise NotImplementedError + + def create(self, data): + """ + Store the image data and return the new image id. + + :raises AlreadyExists if the image already exist. + + """ + raise NotImplementedError + + def update(self, image_id, data): + """Replace the contents of the given image with the new data. + + :raises NotFound if the image does not exist. + + """ + raise NotImplementedError + + def delete(self, image_id): + """ + Delete the given image. + + :raises NotFound if the image does not exist. + + """ + raise NotImplementedError + + def delete_all(self): + """ + Clears out all images + """ + pass + + +class LocalImageService(BaseImageService): -class LocalImageService(ImageService): """Image service storing images to local disk.""" def __init__(self): @@ -88,3 +171,10 @@ class LocalImageService(ImageService): Delete the given image. Raises OSError if the image does not exist. """ os.unlink(self._path_to(image_id)) + + def delete_all(self): + """ + Clears out all images in local directory + """ + for f in os.listdir(self._path): + os.unlink(self._path_to(f)) diff --git a/nova/tests/api/rackspace/test_images.py b/nova/tests/api/rackspace/test_images.py index 489e35052..21dad7648 100644 --- a/nova/tests/api/rackspace/test_images.py +++ b/nova/tests/api/rackspace/test_images.py @@ -15,25 +15,111 @@ # License for the specific language governing permissions and limitations # under the License. +import logging import unittest import stubout +from nova import utils from nova.api.rackspace import images -class ImagesTest(unittest.TestCase): +#{ Fixtures + + +fixture_images = [ + { + 'name': 'image #1', + 'updated': None, + 'created': None, + 'status': None, + 'serverId': None, + 'progress': None}, + { + 'name': 'image #2', + 'updated': None, + 'created': None, + 'status': None, + 'serverId': None, + 'progress': None}, + { + 'name': 'image #3', + 'updated': None, + 'created': None, + 'status': None, + 'serverId': None, + 'progress': None}] + + +#} + + +class BaseImageServiceTests(): + + """Tasks to test for all image services""" + + def test_create_and_index(self): + for i in fixture_images: + self.service.create(i) + + self.assertEquals(len(fixture_images), len(self.service.index())) + + def test_create_and_update(self): + ids = {} + temp = 0 + for i in fixture_images: + ids[self.service.create(i)] = temp + temp += 1 + + self.assertEquals(len(fixture_images), len(self.service.index())) + + for image_id, num in ids.iteritems(): + new_data = fixture_images[num] + new_data['updated'] = 'test' + str(num) + self.service.update(image_id, new_data) + + images = self.service.index() + + for i in images: + self.assertEquals('test' + str(ids[i['id']]), + i['updated']) + + def test_create_and_show(self): + ids = {} + temp = 0 + for i in fixture_images: + ids[self.service.create(i)] = temp + temp += 1 + + for i in fixture_images: + image = self.service.show(i['id']) + index = ids[i['id']] + self.assertEquals(image, fixture_images[index]) + + +class LocalImageServiceTest(unittest.TestCase, + BaseImageServiceTests): + + """Tests the local image service""" + def setUp(self): self.stubs = stubout.StubOutForTesting() + self.service = utils.import_object('nova.image.service.LocalImageService') def tearDown(self): + self.service.delete_all() self.stubs.UnsetAll() - def test_get_image_list(self): - pass - def test_delete_image(self): - pass - - def test_create_image(self): - pass +#class GlanceImageServiceTest(unittest.TestCase, +# BaseImageServiceTests): +# +# """Tests the local image service""" +# +# def setUp(self): +# self.stubs = stubout.StubOutForTesting() +# self.service = utils.import_object('nova.image.service.GlanceImageService') +# +# def tearDown(self): +# self.service.delete_all() +# self.stubs.UnsetAll() -- cgit From 32bd6c198a4ed96768649f58628e22fb25a95855 Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Mon, 4 Oct 2010 16:47:08 -0400 Subject: Adds ParallaxClient and TellerClient plumbing for GlanceImageService. Adds stubs FakeParallaxClient and unit tests for LocalImageService and GlanceImageService. --- nova/image/service.py | 99 ++++++++++++++++++++++-- nova/tests/api/rackspace/fakes.py | 74 ++++++++++++++++++ nova/tests/api/rackspace/test_images.py | 132 ++++++++++++++++---------------- 3 files changed, 230 insertions(+), 75 deletions(-) diff --git a/nova/image/service.py b/nova/image/service.py index 4bceab6ee..3b6d3b6e3 100644 --- a/nova/image/service.py +++ b/nova/image/service.py @@ -16,9 +16,14 @@ # under the License. import cPickle as pickle +import httplib +import json import os.path import random import string +import urlparse + +import webob.exc from nova import utils from nova import flags @@ -27,11 +32,11 @@ from nova import flags FLAGS = flags.FLAGS -flags.DEFINE_string('glance_teller_address', '127.0.0.1', +flags.DEFINE_string('glance_teller_address', 'http://127.0.0.1', 'IP address or URL where Glance\'s Teller service resides') flags.DEFINE_string('glance_teller_port', '9191', 'Port for Glance\'s Teller service') -flags.DEFINE_string('glance_parallax_address', '127.0.0.1', +flags.DEFINE_string('glance_parallax_address', 'http://127.0.0.1', 'IP address or URL where Glance\'s Parallax service resides') flags.DEFINE_string('glance_parallax_port', '9191', 'Port for Glance\'s Parallax service') @@ -80,21 +85,101 @@ class BaseImageService(object): raise NotImplementedError +class TellerClient(object): + + def __init__(self): + self.address = FLAGS.glance_teller_address + self.port = FLAGS.glance_teller_port + url = urlparse.urlparse(self.address) + self.netloc = url.netloc + self.connection_type = {'http': httplib.HTTPConnection, + 'https': httplib.HTTPSConnection}[url.scheme] + + +class ParallaxClient(object): + + def __init__(self): + self.address = FLAGS.glance_parallax_address + self.port = FLAGS.glance_parallax_port + url = urlparse.urlparse(self.address) + self.netloc = url.netloc + self.connection_type = {'http': httplib.HTTPConnection, + 'https': httplib.HTTPSConnection}[url.scheme] + + def get_images(self): + """ + Returns a list of image data mappings from Parallax + """ + try: + c = self.connection_type(self.netloc, self.port) + c.request("GET", "images") + res = c.getresponse() + if res.status == 200: + data = json.loads(res.read()) + return data + else: + # TODO(jaypipes): return or raise HTTP error? + return [] + finally: + c.close() + + def get_image_metadata(self, image_id): + """ + Returns a mapping of image metadata from Parallax + """ + try: + c = self.connection_type(self.netloc, self.port) + c.request("GET", "images/%s" % image_id) + res = c.getresponse() + if res.status == 200: + data = json.loads(res.read()) + return data + else: + # TODO(jaypipes): return or raise HTTP error? + return [] + finally: + c.close() + + def add_image_metadata(self, image_metadata): + """ + Tells parallax about an image's metadata + """ + pass + + def update_image_metadata(self, image_id, image_metadata): + """ + Updates Parallax's information about an image + """ + pass + + def delete_image_metadata(self, image_id): + """ + Deletes Parallax's information about an image + """ + pass + + class GlanceImageService(BaseImageService): """Provides storage and retrieval of disk image objects within Glance.""" + def __init__(self): + self.teller = TellerClient() + self.parallax = ParallaxClient() + def index(self): """ Calls out to Parallax for a list of images available """ - raise NotImplementedError + images = self.parallax.get_images() + return images def show(self, id): """ Returns a dict containing image data for the given opaque image id. """ - raise NotImplementedError + image = self.parallax.get_image_metadata(id) + return image def create(self, data): """ @@ -103,7 +188,7 @@ class GlanceImageService(BaseImageService): :raises AlreadyExists if the image already exist. """ - raise NotImplementedError + return self.parallax.add_image_metadata(data) def update(self, image_id, data): """Replace the contents of the given image with the new data. @@ -111,7 +196,7 @@ class GlanceImageService(BaseImageService): :raises NotFound if the image does not exist. """ - raise NotImplementedError + self.parallax.update_image_metadata(image_id, data) def delete(self, image_id): """ @@ -120,7 +205,7 @@ class GlanceImageService(BaseImageService): :raises NotFound if the image does not exist. """ - raise NotImplementedError + self.parallax.delete_image_metadata(image_id) def delete_all(self): """ diff --git a/nova/tests/api/rackspace/fakes.py b/nova/tests/api/rackspace/fakes.py index 2c4447920..3765b859e 100644 --- a/nova/tests/api/rackspace/fakes.py +++ b/nova/tests/api/rackspace/fakes.py @@ -1,5 +1,24 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 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 datetime import json +import random +import string import webob import webob.dec @@ -7,6 +26,7 @@ import webob.dec from nova import auth from nova import utils from nova import flags +from nova import exception as exc import nova.api.rackspace.auth import nova.api.rackspace._id_translator from nova.image import service @@ -105,6 +125,60 @@ def stub_out_networking(stubs): FLAGS.FAKE_subdomain = 'rs' +def stub_out_glance(stubs): + + class FakeParallaxClient: + + def __init__(self): + self.fixtures = {} + + def fake_get_images(self): + return self.fixtures + + def fake_get_image_metadata(self, image_id): + for k, f in self.fixtures.iteritems(): + if k == image_id: + return f + raise exc.NotFound + + def fake_add_image_metadata(self, image_data): + id = ''.join(random.choice(string.letters) for _ in range(20)) + image_data['id'] = id + self.fixtures[id] = image_data + return id + + def fake_update_image_metadata(self, image_id, image_data): + + if image_id not in self.fixtures.keys(): + raise exc.NotFound + + self.fixtures[image_id].update(image_data) + + def fake_delete_image_metadata(self, image_id): + + if image_id not in self.fixtures.keys(): + raise exc.NotFound + + del self.fixtures[image_id] + + def fake_delete_all(self): + self.fixtures = {} + + fake_parallax_client = FakeParallaxClient() + stubs.Set(nova.image.service.ParallaxClient, 'get_images', + fake_parallax_client.fake_get_images) + stubs.Set(nova.image.service.ParallaxClient, 'get_image_metadata', + fake_parallax_client.fake_get_image_metadata) + stubs.Set(nova.image.service.ParallaxClient, 'add_image_metadata', + fake_parallax_client.fake_add_image_metadata) + stubs.Set(nova.image.service.ParallaxClient, 'update_image_metadata', + fake_parallax_client.fake_update_image_metadata) + stubs.Set(nova.image.service.ParallaxClient, 'delete_image_metadata', + fake_parallax_client.fake_delete_image_metadata) + stubs.Set(nova.image.service.GlanceImageService, 'delete_all', + fake_parallax_client.fake_delete_all) + + class FakeAuthDatabase(object): data = {} diff --git a/nova/tests/api/rackspace/test_images.py b/nova/tests/api/rackspace/test_images.py index 21dad7648..669346680 100644 --- a/nova/tests/api/rackspace/test_images.py +++ b/nova/tests/api/rackspace/test_images.py @@ -22,79 +22,74 @@ import stubout from nova import utils from nova.api.rackspace import images +from nova.tests.api.rackspace import fakes -#{ Fixtures +class BaseImageServiceTests(): + """Tasks to test for all image services""" -fixture_images = [ - { - 'name': 'image #1', - 'updated': None, - 'created': None, - 'status': None, - 'serverId': None, - 'progress': None}, - { - 'name': 'image #2', - 'updated': None, - 'created': None, - 'status': None, - 'serverId': None, - 'progress': None}, - { - 'name': 'image #3', - 'updated': None, - 'created': None, - 'status': None, - 'serverId': None, - 'progress': None}] + def test_create(self): + fixture = {'name': 'test image', + 'updated': None, + 'created': None, + 'status': None, + 'serverId': None, + 'progress': None} -#} + num_images = len(self.service.index()) + id = self.service.create(fixture) -class BaseImageServiceTests(): - - """Tasks to test for all image services""" + self.assertNotEquals(None, id) + self.assertEquals(num_images + 1, len(self.service.index())) - def test_create_and_index(self): - for i in fixture_images: - self.service.create(i) + def test_update(self): - self.assertEquals(len(fixture_images), len(self.service.index())) + fixture = {'name': 'test image', + 'updated': None, + 'created': None, + 'status': None, + 'serverId': None, + 'progress': None} - def test_create_and_update(self): - ids = {} - temp = 0 - for i in fixture_images: - ids[self.service.create(i)] = temp - temp += 1 + id = self.service.create(fixture) - self.assertEquals(len(fixture_images), len(self.service.index())) + fixture['status'] = 'in progress' + + self.service.update(id, fixture) + new_image_data = self.service.show(id) + self.assertEquals('in progress', new_image_data['status']) - for image_id, num in ids.iteritems(): - new_data = fixture_images[num] - new_data['updated'] = 'test' + str(num) - self.service.update(image_id, new_data) + def test_delete(self): - images = self.service.index() + fixtures = [ + {'name': 'test image 1', + 'updated': None, + 'created': None, + 'status': None, + 'serverId': None, + 'progress': None}, + {'name': 'test image 2', + 'updated': None, + 'created': None, + 'status': None, + 'serverId': None, + 'progress': None}] - for i in images: - self.assertEquals('test' + str(ids[i['id']]), - i['updated']) + ids = [] + for fixture in fixtures: + new_id = self.service.create(fixture) + ids.append(new_id) - def test_create_and_show(self): - ids = {} - temp = 0 - for i in fixture_images: - ids[self.service.create(i)] = temp - temp += 1 + num_images = len(self.service.index()) + self.assertEquals(2, num_images) + + self.service.delete(ids[0]) - for i in fixture_images: - image = self.service.show(i['id']) - index = ids[i['id']] - self.assertEquals(image, fixture_images[index]) + num_images = len(self.service.index()) + self.assertEquals(1, num_images) class LocalImageServiceTest(unittest.TestCase, @@ -111,15 +106,16 @@ class LocalImageServiceTest(unittest.TestCase, self.stubs.UnsetAll() -#class GlanceImageServiceTest(unittest.TestCase, -# BaseImageServiceTests): -# -# """Tests the local image service""" -# -# def setUp(self): -# self.stubs = stubout.StubOutForTesting() -# self.service = utils.import_object('nova.image.service.GlanceImageService') -# -# def tearDown(self): -# self.service.delete_all() -# self.stubs.UnsetAll() +class GlanceImageServiceTest(unittest.TestCase, + BaseImageServiceTests): + + """Tests the local image service""" + + def setUp(self): + self.stubs = stubout.StubOutForTesting() + fakes.stub_out_glance(self.stubs) + self.service = utils.import_object('nova.image.service.GlanceImageService') + + def tearDown(self): + self.service.delete_all() + self.stubs.UnsetAll() -- cgit From bf727292794026694c37b84201172b933b41ad2d Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Mon, 4 Oct 2010 17:32:01 -0400 Subject: Update Parallax default port number to match Glance --- nova/image/service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/image/service.py b/nova/image/service.py index 3b6d3b6e3..66be669dd 100644 --- a/nova/image/service.py +++ b/nova/image/service.py @@ -38,7 +38,7 @@ flags.DEFINE_string('glance_teller_port', '9191', 'Port for Glance\'s Teller service') flags.DEFINE_string('glance_parallax_address', 'http://127.0.0.1', 'IP address or URL where Glance\'s Parallax service resides') -flags.DEFINE_string('glance_parallax_port', '9191', +flags.DEFINE_string('glance_parallax_port', '9292', 'Port for Glance\'s Parallax service') -- cgit From b61f4ceff6ea5dbb4d9c63b9f7345c0b31785984 Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Tue, 5 Oct 2010 13:29:27 -0400 Subject: Adds unit test for calling show() on a non-existing image. Changes return from real Parallax service per sirp's recommendation for actual returned dict() values. --- nova/image/service.py | 36 ++++++++++++++++++++++++-------- nova/tests/api/rackspace/fakes.py | 2 +- nova/tests/api/rackspace/test_images.py | 20 ++++++++++++++++++ nova/tests/api/rackspace/test_servers.py | 1 + 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/nova/image/service.py b/nova/image/service.py index 66be669dd..2e570e8a4 100644 --- a/nova/image/service.py +++ b/nova/image/service.py @@ -18,6 +18,7 @@ import cPickle as pickle import httplib import json +import logging import os.path import random import string @@ -27,6 +28,7 @@ import webob.exc from nova import utils from nova import flags +from nova import exception FLAGS = flags.FLAGS @@ -55,6 +57,8 @@ class BaseImageService(object): def show(self, id): """ Returns a dict containing image data for the given opaque image id. + + :raises NotFound if the image does not exist """ raise NotImplementedError @@ -115,10 +119,12 @@ class ParallaxClient(object): c.request("GET", "images") res = c.getresponse() if res.status == 200: - data = json.loads(res.read()) + # Parallax returns a JSONified dict(images=image_list) + data = json.loads(res.read())['images'] return data else: - # TODO(jaypipes): return or raise HTTP error? + logging.warn("Parallax returned HTTP error %d from " + "request for /images", res.status_int) return [] finally: c.close() @@ -132,11 +138,12 @@ class ParallaxClient(object): c.request("GET", "images/%s" % image_id) res = c.getresponse() if res.status == 200: - data = json.loads(res.read()) + # Parallax returns a JSONified dict(image=image_info) + data = json.loads(res.read())['image'] return data else: - # TODO(jaypipes): return or raise HTTP error? - return [] + # TODO(jaypipes): log the error? + return None finally: c.close() @@ -179,7 +186,9 @@ class GlanceImageService(BaseImageService): Returns a dict containing image data for the given opaque image id. """ image = self.parallax.get_image_metadata(id) - return image + if image: + return image + raise exception.NotFound def create(self, data): """ @@ -236,7 +245,10 @@ class LocalImageService(BaseImageService): return [ self.show(id) for id in self._ids() ] def show(self, id): - return pickle.load(open(self._path_to(id))) + try: + return pickle.load(open(self._path_to(id))) + except IOError: + raise exception.NotFound def create(self, data): """ @@ -249,13 +261,19 @@ class LocalImageService(BaseImageService): def update(self, image_id, data): """Replace the contents of the given image with the new data.""" - pickle.dump(data, open(self._path_to(image_id), 'w')) + try: + pickle.dump(data, open(self._path_to(image_id), 'w')) + except IOError: + raise exception.NotFound def delete(self, image_id): """ Delete the given image. Raises OSError if the image does not exist. """ - os.unlink(self._path_to(image_id)) + try: + os.unlink(self._path_to(image_id)) + except IOError: + raise exception.NotFound def delete_all(self): """ diff --git a/nova/tests/api/rackspace/fakes.py b/nova/tests/api/rackspace/fakes.py index 3765b859e..c7d9216c8 100644 --- a/nova/tests/api/rackspace/fakes.py +++ b/nova/tests/api/rackspace/fakes.py @@ -139,7 +139,7 @@ def stub_out_glance(stubs): for k, f in self.fixtures.iteritems(): if k == image_id: return f - raise exc.NotFound + return None def fake_add_image_metadata(self, image_data): id = ''.join(random.choice(string.letters) for _ in range(20)) diff --git a/nova/tests/api/rackspace/test_images.py b/nova/tests/api/rackspace/test_images.py index 669346680..a7f320b46 100644 --- a/nova/tests/api/rackspace/test_images.py +++ b/nova/tests/api/rackspace/test_images.py @@ -20,6 +20,7 @@ import unittest import stubout +from nova import exception from nova import utils from nova.api.rackspace import images from nova.tests.api.rackspace import fakes @@ -45,6 +46,25 @@ class BaseImageServiceTests(): self.assertNotEquals(None, id) self.assertEquals(num_images + 1, len(self.service.index())) + def test_create_and_show_non_existing_image(self): + + fixture = {'name': 'test image', + 'updated': None, + 'created': None, + 'status': None, + 'serverId': None, + 'progress': None} + + num_images = len(self.service.index()) + + id = self.service.create(fixture) + + self.assertNotEquals(None, id) + + self.assertRaises(exception.NotFound, + self.service.show, + 'bad image id') + def test_update(self): fixture = {'name': 'test image', diff --git a/nova/tests/api/rackspace/test_servers.py b/nova/tests/api/rackspace/test_servers.py index 9c1860879..b20a8d432 100644 --- a/nova/tests/api/rackspace/test_servers.py +++ b/nova/tests/api/rackspace/test_servers.py @@ -33,6 +33,7 @@ from nova.tests.api.rackspace import fakes FLAGS = flags.FLAGS +FLAGS.verbose = True def return_server(context, id): return stub_instance(id) -- cgit From fbd1bc015bd5615963b9073eefb895ea04c55a3e Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Tue, 5 Oct 2010 16:19:55 -0400 Subject: Merge overwrote import_object() load of image service. --- nova/api/rackspace/servers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/api/rackspace/servers.py b/nova/api/rackspace/servers.py index 5cfb7a431..b23867bbf 100644 --- a/nova/api/rackspace/servers.py +++ b/nova/api/rackspace/servers.py @@ -42,7 +42,7 @@ def _instance_id_translator(): def _image_service(): """ Helper method for initializing the image id translator """ - service = nova.image.service.ImageService.load() + service = utils.import_object(FLAGS.image_service) return (service, _id_translator.RackspaceAPIIdTranslator( "image", service.__class__.__name__)) -- cgit