From 8e1b88cc228f9ed55c3b6e4fdd790a572d63e6fe Mon Sep 17 00:00:00 2001 From: Eric Day Date: Thu, 18 Nov 2010 13:27:52 -0800 Subject: [PATCH 1/2] First step to getting the image APIs consolidated. The EC2 API was using a one-off S3 image service wrapper, but this should be moved into the nova.image space and use the same interface as the others. There are still some mismatches between the various image service implementations, but this patch was getting large and wanted to keep it within a resonable size. --- nova/api/ec2/cloud.py | 24 ++-- nova/api/ec2/images.py | 123 ------------------ nova/api/openstack/images.py | 13 +- nova/flags.py | 2 +- .../glance/__init__.py => glance.py} | 23 +++- nova/image/local.py | 88 +++++++++++++ nova/image/s3.py | 108 +++++++++++++++ nova/image/service.py | 97 +------------- nova/image/services/__init__.py | 0 nova/tests/api/openstack/fakes.py | 20 ++- nova/tests/api/openstack/test_images.py | 40 +++--- 11 files changed, 271 insertions(+), 267 deletions(-) delete mode 100644 nova/api/ec2/images.py rename nova/image/{services/glance/__init__.py => glance.py} (89%) create mode 100644 nova/image/local.py create mode 100644 nova/image/s3.py delete mode 100644 nova/image/services/__init__.py diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index e2eaa7c5c3..9327bf0d44 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -41,7 +41,7 @@ from nova import rpc from nova import utils from nova.compute.instance_types import INSTANCE_TYPES from nova.api import cloud -from nova.api.ec2 import images +from nova.image.s3 import S3ImageService FLAGS = flags.FLAGS @@ -100,6 +100,7 @@ class CloudController(object): def __init__(self): self.network_manager = utils.import_object(FLAGS.network_manager) self.compute_manager = utils.import_object(FLAGS.compute_manager) + self.image_service = S3ImageService() self.setup() def __str__(self): @@ -785,7 +786,7 @@ class CloudController(object): vpn = kwargs['image_id'] == FLAGS.vpn_image_id if not vpn: - image = images.get(context, kwargs['image_id']) + image = self.image_service.show(context, kwargs['image_id']) # FIXME(ja): if image is vpn, this breaks # get defaults from imagestore @@ -798,8 +799,8 @@ class CloudController(object): ramdisk_id = kwargs.get('ramdisk_id', ramdisk_id) # make sure we have access to kernel and ramdisk - images.get(context, kernel_id) - images.get(context, ramdisk_id) + self.image_service.show(context, kernel_id) + self.image_service.show(context, ramdisk_id) logging.debug("Going to run %s instances...", num_instances) launch_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()) @@ -993,20 +994,17 @@ class CloudController(object): return True def describe_images(self, context, image_id=None, **kwargs): - # The objectstore does its own authorization for describe - imageSet = images.list(context, image_id) + imageSet = self.image_service.index(context, image_id) return {'imagesSet': imageSet} def deregister_image(self, context, image_id, **kwargs): - # FIXME: should the objectstore be doing these authorization checks? - images.deregister(context, image_id) + self.image_service.deregister(context, image_id) return {'imageId': image_id} def register_image(self, context, image_location=None, **kwargs): - # FIXME: should the objectstore be doing these authorization checks? if image_location is None and 'name' in kwargs: image_location = kwargs['name'] - image_id = images.register(context, image_location) + image_id = self.image_service.register(context, image_location) logging.debug("Registered %s as %s" % (image_location, image_id)) return {'imageId': image_id} @@ -1014,7 +1012,7 @@ class CloudController(object): if attribute != 'launchPermission': raise exception.ApiError('attribute not supported: %s' % attribute) try: - image = images.list(context, image_id)[0] + image = self.image_service.show(context, image_id) except IndexError: raise exception.ApiError('invalid id: %s' % image_id) result = {'image_id': image_id, 'launchPermission': []} @@ -1033,8 +1031,8 @@ class CloudController(object): raise exception.ApiError('only group "all" is supported') if not operation_type in ['add', 'remove']: raise exception.ApiError('operation_type must be add or remove') - return images.modify(context, image_id, operation_type) + return self.image_service.modify(context, image_id, operation_type) def update_image(self, context, image_id, **kwargs): - result = images.update(context, image_id, dict(kwargs)) + result = self.image_service.update(context, image_id, dict(kwargs)) return result diff --git a/nova/api/ec2/images.py b/nova/api/ec2/images.py deleted file mode 100644 index 60f9008e94..0000000000 --- a/nova/api/ec2/images.py +++ /dev/null @@ -1,123 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -""" -Proxy AMI-related calls from the cloud controller, to the running -objectstore service. -""" - -import json -import urllib - -import boto.s3.connection - -from nova import exception -from nova import flags -from nova import utils -from nova.auth import manager - - -FLAGS = flags.FLAGS - - -def modify(context, image_id, operation): - conn(context).make_request( - method='POST', - bucket='_images', - query_args=qs({'image_id': image_id, 'operation': operation})) - - return True - - -def update(context, image_id, attributes): - """update an image's attributes / info.json""" - attributes.update({"image_id": image_id}) - conn(context).make_request( - method='POST', - bucket='_images', - query_args=qs(attributes)) - return True - - -def register(context, image_location): - """ rpc call to register a new image based from a manifest """ - - image_id = utils.generate_uid('ami') - conn(context).make_request( - method='PUT', - bucket='_images', - query_args=qs({'image_location': image_location, - 'image_id': image_id})) - - return image_id - - -def list(context, filter_list=[]): - """ return a list of all images that a user can see - - optionally filtered by a list of image_id """ - - if FLAGS.connection_type == 'fake': - return [{'imageId': 'bar'}] - - # FIXME: send along the list of only_images to check for - response = conn(context).make_request( - method='GET', - bucket='_images') - - result = json.loads(response.read()) - if not filter_list is None: - return [i for i in result if i['imageId'] in filter_list] - return result - - -def get(context, image_id): - """return a image object if the context has permissions""" - result = list(context, [image_id]) - if not result: - raise exception.NotFound('Image %s could not be found' % image_id) - image = result[0] - return image - - -def deregister(context, image_id): - """ unregister an image """ - conn(context).make_request( - method='DELETE', - bucket='_images', - query_args=qs({'image_id': image_id})) - - -def conn(context): - access = manager.AuthManager().get_access_key(context.user, - context.project) - secret = str(context.user.secret) - calling = boto.s3.connection.OrdinaryCallingFormat() - return boto.s3.connection.S3Connection(aws_access_key_id=access, - aws_secret_access_key=secret, - is_secure=False, - calling_format=calling, - port=FLAGS.s3_port, - host=FLAGS.s3_host) - - -def qs(params): - pairs = [] - for key in params.keys(): - pairs.append(key + '=' + urllib.quote(params[key])) - return '&'.join(pairs) diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 5bc915e633..cdbdc9bdd8 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -17,6 +17,7 @@ from webob import exc +from nova import context from nova import flags from nova import utils from nova import wsgi @@ -46,19 +47,23 @@ class Controller(wsgi.Controller): def detail(self, req): """Return all public images in detail.""" + user_id = req.environ['nova.context']['user']['id'] + ctxt = context.RequestContext(user_id, user_id) try: - images = self._service.detail() + images = self._service.detail(ctxt) images = nova.api.openstack.limited(images, req) except NotImplementedError: # Emulate detail() using repeated calls to show() - images = self._service.index() + images = self._service.index(ctxt) images = nova.api.openstack.limited(images, req) - images = [self._service.show(i['id']) for i in images] + images = [self._service.show(ctxt, i['id']) for i in images] return dict(images=images) def show(self, req, id): """Return data about the given image id.""" - return dict(image=self._service.show(id)) + user_id = req.environ['nova.context']['user']['id'] + ctxt = context.RequestContext(user_id, user_id) + return dict(image=self._service.show(ctxt, id)) def delete(self, req, id): # Only public images are supported for now. diff --git a/nova/flags.py b/nova/flags.py index 4ae86d9b2c..07b469bca8 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -232,7 +232,7 @@ 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', +DEFINE_string('image_service', 'nova.image.local.LocalImageService', 'The service to use for retrieving and searching for images.') DEFINE_string('host', socket.gethostname(), diff --git a/nova/image/services/glance/__init__.py b/nova/image/glance.py similarity index 89% rename from nova/image/services/glance/__init__.py rename to nova/image/glance.py index f1d05f0bc7..547381a4ab 100644 --- a/nova/image/services/glance/__init__.py +++ b/nova/image/glance.py @@ -31,6 +31,17 @@ import nova.image.service FLAGS = flags.FLAGS +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', 'http://127.0.0.1', + 'IP address or URL where Glance\'s Parallax service ' + 'resides') +flags.DEFINE_string('glance_parallax_port', '9292', + 'Port for Glance\'s Parallax service') + + class TellerClient(object): def __init__(self): @@ -160,21 +171,21 @@ class GlanceImageService(nova.image.service.BaseImageService): self.teller = TellerClient() self.parallax = ParallaxClient() - def index(self): + def index(self, context): """ Calls out to Parallax for a list of images available """ images = self.parallax.get_image_index() return images - def detail(self): + def detail(self, context): """ Calls out to Parallax for a list of detailed image information """ images = self.parallax.get_image_details() return images - def show(self, id): + def show(self, context, id): """ Returns a dict containing image data for the given opaque image id. """ @@ -183,7 +194,7 @@ class GlanceImageService(nova.image.service.BaseImageService): return image raise exception.NotFound - def create(self, data): + def create(self, context, data): """ Store the image data and return the new image id. @@ -192,7 +203,7 @@ class GlanceImageService(nova.image.service.BaseImageService): """ return self.parallax.add_image_metadata(data) - def update(self, image_id, data): + def update(self, context, image_id, data): """Replace the contents of the given image with the new data. :raises NotFound if the image does not exist. @@ -200,7 +211,7 @@ class GlanceImageService(nova.image.service.BaseImageService): """ self.parallax.update_image_metadata(image_id, data) - def delete(self, image_id): + def delete(self, context, image_id): """ Delete the given image. diff --git a/nova/image/local.py b/nova/image/local.py new file mode 100644 index 0000000000..9b0cdcc50d --- /dev/null +++ b/nova/image/local.py @@ -0,0 +1,88 @@ +# 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 cPickle as pickle +import os.path +import random + +from nova import exception +from nova.image import service + + +class LocalImageService(service.BaseImageService): + + """Image service storing images to local disk. + + It assumes that image_ids are integers.""" + + def __init__(self): + self._path = "/tmp/nova/images" + try: + os.makedirs(self._path) + except OSError: # Exists + pass + + def _path_to(self, image_id): + return os.path.join(self._path, str(image_id)) + + def _ids(self): + """The list of all image ids.""" + return [int(i) for i in os.listdir(self._path)] + + def index(self, context): + return [dict(id=i['id'], name=i['name']) for i in self.detail(context)] + + def detail(self, context): + return [self.show(context, id) for id in self._ids()] + + def show(self, context, id): + try: + return pickle.load(open(self._path_to(id))) + except IOError: + raise exception.NotFound + + def create(self, context, data): + """ + Store the image data and return the new image id. + """ + id = random.randint(0, 2 ** 32 - 1) + data['id'] = id + self.update(context, id, data) + return id + + def update(self, context, image_id, data): + """Replace the contents of the given image with the new data.""" + try: + pickle.dump(data, open(self._path_to(image_id), 'w')) + except IOError: + raise exception.NotFound + + def delete(self, context, image_id): + """ + Delete the given image. Raises OSError if the image does not exist. + """ + try: + os.unlink(self._path_to(image_id)) + except IOError: + raise exception.NotFound + + def delete_all(self): + """ + Clears out all images in local directory + """ + for id in self._ids(): + os.unlink(self._path_to(id)) diff --git a/nova/image/s3.py b/nova/image/s3.py new file mode 100644 index 0000000000..ba1086aca9 --- /dev/null +++ b/nova/image/s3.py @@ -0,0 +1,108 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# 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. + +""" +Proxy AMI-related calls from the cloud controller, to the running +objectstore service. +""" + +import json +import urllib + +import boto.s3.connection + +from nova import exception +from nova import flags +from nova import utils +from nova.auth import manager +from nova.image import service + + +FLAGS = flags.FLAGS + + +class S3ImageService(service.BaseImageService): + + def modify(self, context, image_id, operation): + self._conn(context).make_request( + method='POST', + bucket='_images', + query_args=self._qs({'image_id': image_id, 'operation': operation})) + return True + + def update(self, context, image_id, attributes): + """update an image's attributes / info.json""" + attributes.update({"image_id": image_id}) + self._conn(context).make_request( + method='POST', + bucket='_images', + query_args=self._qs(attributes)) + return True + + def register(self, context, image_location): + """ rpc call to register a new image based from a manifest """ + image_id = utils.generate_uid('ami') + self._conn(context).make_request( + method='PUT', + bucket='_images', + query_args=self._qs({'image_location': image_location, + 'image_id': image_id})) + return image_id + + def index(self, context): + """Return a list of all images that a user can see.""" + response = self._conn(context).make_request( + method='GET', + bucket='_images') + return json.loads(response.read()) + + def show(self, context, image_id): + """return a image object if the context has permissions""" + if FLAGS.connection_type == 'fake': + return {'imageId': 'bar'} + result = self.index(context) + result = [i for i in result if i['imageId'] == image_id] + if not result: + raise exception.NotFound('Image %s could not be found' % image_id) + image = result[0] + return image + + def deregister(self, context, image_id): + """ unregister an image """ + self._conn(context).make_request( + method='DELETE', + bucket='_images', + query_args=self._qs({'image_id': image_id})) + + def _conn(self, context): + access = manager.AuthManager().get_access_key(context.user, + context.project) + secret = str(context.user.secret) + calling = boto.s3.connection.OrdinaryCallingFormat() + return boto.s3.connection.S3Connection(aws_access_key_id=access, + aws_secret_access_key=secret, + is_secure=False, + calling_format=calling, + port=FLAGS.s3_port, + host=FLAGS.s3_host) + + def _qs(self, params): + pairs = [] + for key in params.keys(): + pairs.append(key + '=' + urllib.quote(params[key])) + return '&'.join(pairs) diff --git a/nova/image/service.py b/nova/image/service.py index 52ddd4e0f9..ebee2228d5 100644 --- a/nova/image/service.py +++ b/nova/image/service.py @@ -15,32 +15,12 @@ # License for the specific language governing permissions and limitations # under the License. -import cPickle as pickle -import os.path -import random - -from nova import flags -from nova import exception - -FLAGS = flags.FLAGS - - -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', 'http://127.0.0.1', - 'IP address or URL where Glance\'s Parallax service ' - 'resides') -flags.DEFINE_string('glance_parallax_port', '9292', - 'Port for Glance\'s Parallax service') - class BaseImageService(object): """Base class for providing image search and retrieval services""" - def index(self): + def index(self, context): """ Returns a sequence of mappings of id and name information about images. @@ -52,7 +32,7 @@ class BaseImageService(object): """ raise NotImplementedError - def detail(self): + def detail(self, context): """ Returns a sequence of mappings of detailed information about images. @@ -76,7 +56,7 @@ class BaseImageService(object): """ raise NotImplementedError - def show(self, id): + def show(self, context, id): """ Returns a dict containing image data for the given opaque image id. @@ -96,7 +76,7 @@ class BaseImageService(object): """ raise NotImplementedError - def create(self, data): + def create(self, context, data): """ Store the image data and return the new image id. @@ -105,7 +85,7 @@ class BaseImageService(object): """ raise NotImplementedError - def update(self, image_id, data): + def update(self, context, image_id, data): """Replace the contents of the given image with the new data. :raises NotFound if the image does not exist. @@ -113,7 +93,7 @@ class BaseImageService(object): """ raise NotImplementedError - def delete(self, image_id): + def delete(self, context, image_id): """ Delete the given image. @@ -121,68 +101,3 @@ class BaseImageService(object): """ raise NotImplementedError - - -class LocalImageService(BaseImageService): - - """Image service storing images to local disk. - - It assumes that image_ids are integers.""" - - def __init__(self): - self._path = "/tmp/nova/images" - try: - os.makedirs(self._path) - except OSError: # Exists - pass - - def _path_to(self, image_id): - return os.path.join(self._path, str(image_id)) - - def _ids(self): - """The list of all image ids.""" - return [int(i) for i in os.listdir(self._path)] - - def index(self): - return [dict(id=i['id'], name=i['name']) for i in self.detail()] - - def detail(self): - return [self.show(id) for id in self._ids()] - - def show(self, id): - try: - return pickle.load(open(self._path_to(id))) - except IOError: - raise exception.NotFound - - def create(self, data): - """ - Store the image data and return the new image id. - """ - id = random.randint(0, 2 ** 32 - 1) - data['id'] = id - self.update(id, data) - return id - - def update(self, image_id, data): - """Replace the contents of the given image with the new data.""" - 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. - """ - try: - os.unlink(self._path_to(image_id)) - except IOError: - raise exception.NotFound - - def delete_all(self): - """ - Clears out all images in local directory - """ - for id in self._ids(): - os.unlink(self._path_to(id)) diff --git a/nova/image/services/__init__.py b/nova/image/services/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py index 52b3926010..639a2ebe4e 100644 --- a/nova/tests/api/openstack/fakes.py +++ b/nova/tests/api/openstack/fakes.py @@ -29,7 +29,7 @@ from nova import flags from nova import exception as exc import nova.api.openstack.auth from nova.image import service -from nova.image.services import glance +from nova.image import glance from nova.tests import fake_flags from nova.wsgi import Router @@ -76,7 +76,7 @@ def stub_out_image_service(stubs): def fake_image_show(meh, id): return dict(kernelId=1, ramdiskId=1) - stubs.Set(nova.image.service.LocalImageService, 'show', fake_image_show) + stubs.Set(nova.image.local.LocalImageService, 'show', fake_image_show) def stub_out_auth(stubs): @@ -151,21 +151,19 @@ def stub_out_glance(stubs, initial_fixtures=[]): self.fixtures = [] fake_parallax_client = FakeParallaxClient(initial_fixtures) - stubs.Set(nova.image.services.glance.ParallaxClient, 'get_image_index', + stubs.Set(nova.image.glance.ParallaxClient, 'get_image_index', fake_parallax_client.fake_get_image_index) - stubs.Set(nova.image.services.glance.ParallaxClient, 'get_image_details', + stubs.Set(nova.image.glance.ParallaxClient, 'get_image_details', fake_parallax_client.fake_get_image_details) - stubs.Set(nova.image.services.glance.ParallaxClient, 'get_image_metadata', + stubs.Set(nova.image.glance.ParallaxClient, 'get_image_metadata', fake_parallax_client.fake_get_image_metadata) - stubs.Set(nova.image.services.glance.ParallaxClient, 'add_image_metadata', + stubs.Set(nova.image.glance.ParallaxClient, 'add_image_metadata', fake_parallax_client.fake_add_image_metadata) - stubs.Set(nova.image.services.glance.ParallaxClient, - 'update_image_metadata', + stubs.Set(nova.image.glance.ParallaxClient, 'update_image_metadata', fake_parallax_client.fake_update_image_metadata) - stubs.Set(nova.image.services.glance.ParallaxClient, - 'delete_image_metadata', + stubs.Set(nova.image.glance.ParallaxClient, 'delete_image_metadata', fake_parallax_client.fake_delete_image_metadata) - stubs.Set(nova.image.services.glance.GlanceImageService, 'delete_all', + stubs.Set(nova.image.glance.GlanceImageService, 'delete_all', fake_parallax_client.fake_delete_all) diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index 0f3941c29d..207947b3c2 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -28,6 +28,7 @@ import unittest import stubout import webob +from nova import context from nova import exception from nova import flags from nova import utils @@ -52,12 +53,12 @@ class BaseImageServiceTests(object): 'serverId': None, 'progress': None} - num_images = len(self.service.index()) + num_images = len(self.service.index(self.context)) - id = self.service.create(fixture) + id = self.service.create(self.context, fixture) self.assertNotEquals(None, id) - self.assertEquals(num_images + 1, len(self.service.index())) + self.assertEquals(num_images + 1, len(self.service.index(self.context))) def test_create_and_show_non_existing_image(self): @@ -68,14 +69,15 @@ class BaseImageServiceTests(object): 'serverId': None, 'progress': None} - num_images = len(self.service.index()) + num_images = len(self.service.index(self.context)) - id = self.service.create(fixture) + id = self.service.create(self.context, fixture) self.assertNotEquals(None, id) self.assertRaises(exception.NotFound, self.service.show, + self.context, 'bad image id') def test_update(self): @@ -87,12 +89,12 @@ class BaseImageServiceTests(object): 'serverId': None, 'progress': None} - id = self.service.create(fixture) + id = self.service.create(self.context, fixture) fixture['status'] = 'in progress' - self.service.update(id, fixture) - new_image_data = self.service.show(id) + self.service.update(self.context, id, fixture) + new_image_data = self.service.show(self.context, id) self.assertEquals('in progress', new_image_data['status']) def test_delete(self): @@ -111,20 +113,20 @@ class BaseImageServiceTests(object): 'serverId': None, 'progress': None}] - num_images = len(self.service.index()) - self.assertEquals(0, num_images, str(self.service.index())) + num_images = len(self.service.index(self.context)) + self.assertEquals(0, num_images, str(self.service.index(self.context))) ids = [] for fixture in fixtures: - new_id = self.service.create(fixture) + new_id = self.service.create(self.context, fixture) ids.append(new_id) - num_images = len(self.service.index()) - self.assertEquals(2, num_images, str(self.service.index())) + num_images = len(self.service.index(self.context)) + self.assertEquals(2, num_images, str(self.service.index(self.context))) - self.service.delete(ids[0]) + self.service.delete(self.context, ids[0]) - num_images = len(self.service.index()) + num_images = len(self.service.index(self.context)) self.assertEquals(1, num_images) @@ -135,8 +137,9 @@ class LocalImageServiceTest(unittest.TestCase, def setUp(self): self.stubs = stubout.StubOutForTesting() - service_class = 'nova.image.service.LocalImageService' + service_class = 'nova.image.local.LocalImageService' self.service = utils.import_object(service_class) + self.context = context.RequestContext(None, None) def tearDown(self): self.service.delete_all() @@ -151,8 +154,9 @@ class GlanceImageServiceTest(unittest.TestCase, def setUp(self): self.stubs = stubout.StubOutForTesting() fakes.stub_out_glance(self.stubs) - service_class = 'nova.image.services.glance.GlanceImageService' + service_class = 'nova.image.glance.GlanceImageService' self.service = utils.import_object(service_class) + self.context = context.RequestContext(None, None) self.service.delete_all() def tearDown(self): @@ -187,7 +191,7 @@ class ImageControllerWithGlanceServiceTest(unittest.TestCase): def setUp(self): self.orig_image_service = FLAGS.image_service - FLAGS.image_service = 'nova.image.services.glance.GlanceImageService' + FLAGS.image_service = 'nova.image.glance.GlanceImageService' self.stubs = stubout.StubOutForTesting() fakes.FakeAuthManager.auth_data = {} fakes.FakeAuthDatabase.data = {} From 9c7ddf24acfdbdb220bcc56d8e4d6421cd46e1d7 Mon Sep 17 00:00:00 2001 From: Eric Day Date: Thu, 18 Nov 2010 21:27:00 -0800 Subject: [PATCH 2/2] PEP8 fixes, 2 lines were too long. --- nova/image/s3.py | 3 ++- nova/tests/api/openstack/test_images.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/nova/image/s3.py b/nova/image/s3.py index ba1086aca9..0a25161de4 100644 --- a/nova/image/s3.py +++ b/nova/image/s3.py @@ -42,7 +42,8 @@ class S3ImageService(service.BaseImageService): self._conn(context).make_request( method='POST', bucket='_images', - query_args=self._qs({'image_id': image_id, 'operation': operation})) + query_args=self._qs({'image_id': image_id, + 'operation': operation})) return True def update(self, context, image_id, attributes): diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index 207947b3c2..f610cbf9cf 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -58,7 +58,8 @@ class BaseImageServiceTests(object): id = self.service.create(self.context, fixture) self.assertNotEquals(None, id) - self.assertEquals(num_images + 1, len(self.service.index(self.context))) + self.assertEquals(num_images + 1, + len(self.service.index(self.context))) def test_create_and_show_non_existing_image(self):