removing local image service
This commit is contained in:
@@ -120,6 +120,14 @@ class _FakeImageService(service.BaseImageService):
|
|||||||
image_id, self.images)
|
image_id, self.images)
|
||||||
raise exception.ImageNotFound(image_id=image_id)
|
raise exception.ImageNotFound(image_id=image_id)
|
||||||
|
|
||||||
|
def show_by_name(self, context, name):
|
||||||
|
"""Returns a dict containing image data for the given name."""
|
||||||
|
images = copy.deepcopy(self.images.values())
|
||||||
|
for image in images:
|
||||||
|
if name == image.get('name'):
|
||||||
|
return image
|
||||||
|
raise exception.ImageNotFound(image_id=name)
|
||||||
|
|
||||||
def create(self, context, metadata, data=None):
|
def create(self, context, metadata, data=None):
|
||||||
"""Store the image data and return the new image id.
|
"""Store the image data and return the new image id.
|
||||||
|
|
||||||
|
|||||||
@@ -1,167 +0,0 @@
|
|||||||
# 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 json
|
|
||||||
import os.path
|
|
||||||
import random
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
from nova import exception
|
|
||||||
from nova import flags
|
|
||||||
from nova import log as logging
|
|
||||||
from nova import utils
|
|
||||||
from nova.image import service
|
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
flags.DEFINE_string('images_path', '$state_path/images',
|
|
||||||
'path to decrypted images')
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger('nova.image.local')
|
|
||||||
|
|
||||||
|
|
||||||
class LocalImageService(service.BaseImageService):
|
|
||||||
"""Image service storing images to local disk.
|
|
||||||
|
|
||||||
It assumes that image_ids are integers.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self._path = FLAGS.images_path
|
|
||||||
|
|
||||||
def _path_to(self, image_id, fname='info.json'):
|
|
||||||
if fname:
|
|
||||||
return os.path.join(self._path, '%08x' % int(image_id), fname)
|
|
||||||
return os.path.join(self._path, '%08x' % int(image_id))
|
|
||||||
|
|
||||||
def _ids(self):
|
|
||||||
"""The list of all image ids."""
|
|
||||||
images = []
|
|
||||||
for image_dir in os.listdir(self._path):
|
|
||||||
try:
|
|
||||||
unhexed_image_id = int(image_dir, 16)
|
|
||||||
except ValueError:
|
|
||||||
LOG.error(_('%s is not in correct directory naming format')
|
|
||||||
% image_dir)
|
|
||||||
else:
|
|
||||||
images.append(unhexed_image_id)
|
|
||||||
return images
|
|
||||||
|
|
||||||
def index(self, context, filters=None, marker=None, limit=None):
|
|
||||||
# TODO(blamar): Make use of filters, marker, and limit
|
|
||||||
filtered = []
|
|
||||||
image_metas = self.detail(context)
|
|
||||||
for image_meta in image_metas:
|
|
||||||
meta = utils.subset_dict(image_meta, ('id', 'name'))
|
|
||||||
filtered.append(meta)
|
|
||||||
return filtered
|
|
||||||
|
|
||||||
def detail(self, context, filters=None, marker=None, limit=None):
|
|
||||||
# TODO(blamar): Make use of filters, marker, and limit
|
|
||||||
images = []
|
|
||||||
for image_id in self._ids():
|
|
||||||
try:
|
|
||||||
image = self.show(context, image_id)
|
|
||||||
images.append(image)
|
|
||||||
except exception.NotFound:
|
|
||||||
continue
|
|
||||||
return images
|
|
||||||
|
|
||||||
def show(self, context, image_id):
|
|
||||||
try:
|
|
||||||
with open(self._path_to(image_id)) as metadata_file:
|
|
||||||
image_meta = json.load(metadata_file)
|
|
||||||
if not self._is_image_available(context, image_meta):
|
|
||||||
raise exception.ImageNotFound(image_id=image_id)
|
|
||||||
return image_meta
|
|
||||||
except (IOError, ValueError):
|
|
||||||
raise exception.ImageNotFound(image_id=image_id)
|
|
||||||
|
|
||||||
def show_by_name(self, context, name):
|
|
||||||
"""Returns a dict containing image data for the given name."""
|
|
||||||
# NOTE(vish): Not very efficient, but the local image service
|
|
||||||
# is for testing so it should be fine.
|
|
||||||
images = self.detail(context)
|
|
||||||
image = None
|
|
||||||
for cantidate in images:
|
|
||||||
if name == cantidate.get('name'):
|
|
||||||
image = cantidate
|
|
||||||
break
|
|
||||||
if image is None:
|
|
||||||
raise exception.ImageNotFound(image_id=name)
|
|
||||||
return image
|
|
||||||
|
|
||||||
def get(self, context, image_id, data):
|
|
||||||
"""Get image and metadata."""
|
|
||||||
try:
|
|
||||||
with open(self._path_to(image_id)) as metadata_file:
|
|
||||||
metadata = json.load(metadata_file)
|
|
||||||
with open(self._path_to(image_id, 'image')) as image_file:
|
|
||||||
shutil.copyfileobj(image_file, data)
|
|
||||||
except (IOError, ValueError):
|
|
||||||
raise exception.ImageNotFound(image_id=image_id)
|
|
||||||
return metadata
|
|
||||||
|
|
||||||
def create(self, context, metadata, data=None):
|
|
||||||
"""Store the image data and return the new image."""
|
|
||||||
image_id = random.randint(0, 2 ** 31 - 1)
|
|
||||||
image_path = self._path_to(image_id, None)
|
|
||||||
if not os.path.exists(image_path):
|
|
||||||
os.mkdir(image_path)
|
|
||||||
return self._store(context, image_id, metadata, data)
|
|
||||||
|
|
||||||
def update(self, context, image_id, metadata, data=None):
|
|
||||||
"""Replace the contents of the given image with the new data."""
|
|
||||||
# NOTE(vish): show is to check if image is available
|
|
||||||
self.show(context, image_id)
|
|
||||||
return self._store(context, image_id, metadata, data)
|
|
||||||
|
|
||||||
def _store(self, context, image_id, metadata, data=None):
|
|
||||||
metadata['id'] = image_id
|
|
||||||
try:
|
|
||||||
if data:
|
|
||||||
location = self._path_to(image_id, 'image')
|
|
||||||
with open(location, 'w') as image_file:
|
|
||||||
shutil.copyfileobj(data, image_file)
|
|
||||||
# NOTE(vish): update metadata similarly to glance
|
|
||||||
metadata['status'] = 'active'
|
|
||||||
metadata['location'] = location
|
|
||||||
with open(self._path_to(image_id), 'w') as metadata_file:
|
|
||||||
json.dump(metadata, metadata_file)
|
|
||||||
except (IOError, ValueError):
|
|
||||||
raise exception.ImageNotFound(image_id=image_id)
|
|
||||||
return metadata
|
|
||||||
|
|
||||||
def delete(self, context, image_id):
|
|
||||||
"""Delete the given image.
|
|
||||||
|
|
||||||
:raises: ImageNotFound if the image does not exist.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# NOTE(vish): show is to check if image is available
|
|
||||||
self.show(context, image_id)
|
|
||||||
try:
|
|
||||||
shutil.rmtree(self._path_to(image_id, None))
|
|
||||||
except (IOError, ValueError):
|
|
||||||
raise exception.ImageNotFound(image_id=image_id)
|
|
||||||
|
|
||||||
def delete_all(self):
|
|
||||||
"""Clears out all images in local directory."""
|
|
||||||
for image_id in self._ids():
|
|
||||||
shutil.rmtree(self._path_to(image_id, None))
|
|
||||||
@@ -39,7 +39,6 @@ from nova.api.openstack import limits
|
|||||||
from nova.auth.manager import User, Project
|
from nova.auth.manager import User, Project
|
||||||
import nova.image.fake
|
import nova.image.fake
|
||||||
from nova.image import glance
|
from nova.image import glance
|
||||||
from nova.image import local
|
|
||||||
from nova.image import service
|
from nova.image import service
|
||||||
from nova.tests import fake_flags
|
from nova.tests import fake_flags
|
||||||
from nova.wsgi import Router
|
from nova.wsgi import Router
|
||||||
|
|||||||
@@ -135,36 +135,6 @@ class _BaseImageServiceTests(test.TestCase):
|
|||||||
return fixture
|
return fixture
|
||||||
|
|
||||||
|
|
||||||
class LocalImageServiceTest(_BaseImageServiceTests):
|
|
||||||
|
|
||||||
"""Tests the local image service"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(LocalImageServiceTest, self).setUp()
|
|
||||||
self.tempdir = tempfile.mkdtemp()
|
|
||||||
self.flags(images_path=self.tempdir)
|
|
||||||
self.stubs = stubout.StubOutForTesting()
|
|
||||||
service_class = 'nova.image.local.LocalImageService'
|
|
||||||
self.service = utils.import_object(service_class)
|
|
||||||
self.context = context.RequestContext(None, None)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
shutil.rmtree(self.tempdir)
|
|
||||||
self.stubs.UnsetAll()
|
|
||||||
super(LocalImageServiceTest, self).tearDown()
|
|
||||||
|
|
||||||
def test_get_all_ids_with_incorrect_directory_formats(self):
|
|
||||||
# create some old-style image directories (starting with 'ami-')
|
|
||||||
for x in [1, 2, 3]:
|
|
||||||
tempfile.mkstemp(prefix='ami-', dir=self.tempdir)
|
|
||||||
# create some valid image directories names
|
|
||||||
for x in ["1485baed", "1a60f0ee", "3123a73d"]:
|
|
||||||
os.makedirs(os.path.join(self.tempdir, x))
|
|
||||||
found_image_ids = self.service._ids()
|
|
||||||
self.assertEqual(True, isinstance(found_image_ids, list))
|
|
||||||
self.assertEqual(3, len(found_image_ids), len(found_image_ids))
|
|
||||||
|
|
||||||
|
|
||||||
class GlanceImageServiceTest(_BaseImageServiceTests):
|
class GlanceImageServiceTest(_BaseImageServiceTests):
|
||||||
|
|
||||||
"""Tests the Glance image service, in particular that metadata translation
|
"""Tests the Glance image service, in particular that metadata translation
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ flags.DECLARE('fake_network', 'nova.network.manager')
|
|||||||
FLAGS['network_size'].SetDefault(8)
|
FLAGS['network_size'].SetDefault(8)
|
||||||
FLAGS['num_networks'].SetDefault(2)
|
FLAGS['num_networks'].SetDefault(2)
|
||||||
FLAGS['fake_network'].SetDefault(True)
|
FLAGS['fake_network'].SetDefault(True)
|
||||||
FLAGS['image_service'].SetDefault('nova.image.local.LocalImageService')
|
FLAGS['image_service'].SetDefault('nova.image.fake.FakeImageService')
|
||||||
flags.DECLARE('num_shelves', 'nova.volume.driver')
|
flags.DECLARE('num_shelves', 'nova.volume.driver')
|
||||||
flags.DECLARE('blades_per_shelf', 'nova.volume.driver')
|
flags.DECLARE('blades_per_shelf', 'nova.volume.driver')
|
||||||
flags.DECLARE('iscsi_num_targets', 'nova.volume.driver')
|
flags.DECLARE('iscsi_num_targets', 'nova.volume.driver')
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ from nova import utils
|
|||||||
from nova.auth import manager
|
from nova.auth import manager
|
||||||
from nova.api.ec2 import cloud
|
from nova.api.ec2 import cloud
|
||||||
from nova.api.ec2 import ec2utils
|
from nova.api.ec2 import ec2utils
|
||||||
from nova.image import local
|
from nova.image import fake
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
@@ -69,8 +69,8 @@ class CloudTestCase(test.TestCase):
|
|||||||
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
|
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
|
||||||
'type': 'machine', 'image_state': 'available'}}
|
'type': 'machine', 'image_state': 'available'}}
|
||||||
|
|
||||||
self.stubs.Set(local.LocalImageService, 'show', fake_show)
|
self.stubs.Set(fake._FakeImageService, 'show', fake_show)
|
||||||
self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show)
|
self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show)
|
||||||
|
|
||||||
# NOTE(vish): set up a manual wait so rpc.cast has a chance to finish
|
# NOTE(vish): set up a manual wait so rpc.cast has a chance to finish
|
||||||
rpc_cast = rpc.cast
|
rpc_cast = rpc.cast
|
||||||
@@ -291,7 +291,7 @@ class CloudTestCase(test.TestCase):
|
|||||||
def fake_show_none(meh, context, id):
|
def fake_show_none(meh, context, id):
|
||||||
raise exception.ImageNotFound(image_id='bad_image_id')
|
raise exception.ImageNotFound(image_id='bad_image_id')
|
||||||
|
|
||||||
self.stubs.Set(local.LocalImageService, 'detail', fake_detail)
|
self.stubs.Set(fake._FakeImageService, 'detail', fake_detail)
|
||||||
# list all
|
# list all
|
||||||
result1 = describe_images(self.context)
|
result1 = describe_images(self.context)
|
||||||
result1 = result1['imagesSet'][0]
|
result1 = result1['imagesSet'][0]
|
||||||
@@ -305,8 +305,8 @@ class CloudTestCase(test.TestCase):
|
|||||||
self.assertEqual(2, len(result3['imagesSet']))
|
self.assertEqual(2, len(result3['imagesSet']))
|
||||||
# provide an non-existing image_id
|
# provide an non-existing image_id
|
||||||
self.stubs.UnsetAll()
|
self.stubs.UnsetAll()
|
||||||
self.stubs.Set(local.LocalImageService, 'show', fake_show_none)
|
self.stubs.Set(fake._FakeImageService, 'show', fake_show_none)
|
||||||
self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show_none)
|
self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show_none)
|
||||||
self.assertRaises(exception.ImageNotFound, describe_images,
|
self.assertRaises(exception.ImageNotFound, describe_images,
|
||||||
self.context, ['ami-fake'])
|
self.context, ['ami-fake'])
|
||||||
|
|
||||||
@@ -317,8 +317,8 @@ class CloudTestCase(test.TestCase):
|
|||||||
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
|
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
|
||||||
'type': 'machine'}, 'is_public': True}
|
'type': 'machine'}, 'is_public': True}
|
||||||
|
|
||||||
self.stubs.Set(local.LocalImageService, 'show', fake_show)
|
self.stubs.Set(fake._FakeImageService, 'show', fake_show)
|
||||||
self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show)
|
self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show)
|
||||||
result = describe_image_attribute(self.context, 'ami-00000001',
|
result = describe_image_attribute(self.context, 'ami-00000001',
|
||||||
'launchPermission')
|
'launchPermission')
|
||||||
self.assertEqual([{'group': 'all'}], result['launchPermission'])
|
self.assertEqual([{'group': 'all'}], result['launchPermission'])
|
||||||
@@ -333,9 +333,9 @@ class CloudTestCase(test.TestCase):
|
|||||||
def fake_update(meh, context, image_id, metadata, data=None):
|
def fake_update(meh, context, image_id, metadata, data=None):
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
self.stubs.Set(local.LocalImageService, 'show', fake_show)
|
self.stubs.Set(fake._FakeImageService, 'show', fake_show)
|
||||||
self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show)
|
self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show)
|
||||||
self.stubs.Set(local.LocalImageService, 'update', fake_update)
|
self.stubs.Set(fake._FakeImageService, 'update', fake_update)
|
||||||
result = modify_image_attribute(self.context, 'ami-00000001',
|
result = modify_image_attribute(self.context, 'ami-00000001',
|
||||||
'launchPermission', 'add',
|
'launchPermission', 'add',
|
||||||
user_group=['all'])
|
user_group=['all'])
|
||||||
@@ -347,7 +347,7 @@ class CloudTestCase(test.TestCase):
|
|||||||
def fake_delete(self, context, id):
|
def fake_delete(self, context, id):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
self.stubs.Set(local.LocalImageService, 'delete', fake_delete)
|
self.stubs.Set(fake._FakeImageService, 'delete', fake_delete)
|
||||||
# valid image
|
# valid image
|
||||||
result = deregister_image(self.context, 'ami-00000001')
|
result = deregister_image(self.context, 'ami-00000001')
|
||||||
self.assertEqual(result['imageId'], 'ami-00000001')
|
self.assertEqual(result['imageId'], 'ami-00000001')
|
||||||
@@ -357,7 +357,7 @@ class CloudTestCase(test.TestCase):
|
|||||||
def fake_detail_empty(self, context):
|
def fake_detail_empty(self, context):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
self.stubs.Set(local.LocalImageService, 'detail', fake_detail_empty)
|
self.stubs.Set(fake._FakeImageService, 'detail', fake_detail_empty)
|
||||||
self.assertRaises(exception.ImageNotFound, deregister_image,
|
self.assertRaises(exception.ImageNotFound, deregister_image,
|
||||||
self.context, 'ami-bad001')
|
self.context, 'ami-bad001')
|
||||||
|
|
||||||
@@ -468,7 +468,7 @@ class CloudTestCase(test.TestCase):
|
|||||||
'type': 'machine'}}
|
'type': 'machine'}}
|
||||||
|
|
||||||
self.stubs.UnsetAll()
|
self.stubs.UnsetAll()
|
||||||
self.stubs.Set(local.LocalImageService, 'show', fake_show_no_state)
|
self.stubs.Set(fake._FakeImageService, 'show', fake_show_no_state)
|
||||||
self.assertRaises(exception.ApiError, run_instances,
|
self.assertRaises(exception.ApiError, run_instances,
|
||||||
self.context, **kwargs)
|
self.context, **kwargs)
|
||||||
|
|
||||||
@@ -483,7 +483,7 @@ class CloudTestCase(test.TestCase):
|
|||||||
'type': 'machine', 'image_state': 'decrypting'}}
|
'type': 'machine', 'image_state': 'decrypting'}}
|
||||||
|
|
||||||
self.stubs.UnsetAll()
|
self.stubs.UnsetAll()
|
||||||
self.stubs.Set(local.LocalImageService, 'show', fake_show_decrypt)
|
self.stubs.Set(fake._FakeImageService, 'show', fake_show_decrypt)
|
||||||
self.assertRaises(exception.ApiError, run_instances,
|
self.assertRaises(exception.ApiError, run_instances,
|
||||||
self.context, **kwargs)
|
self.context, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -22,21 +22,21 @@ Tests For Compute
|
|||||||
import mox
|
import mox
|
||||||
import stubout
|
import stubout
|
||||||
|
|
||||||
|
from nova.auth import manager
|
||||||
from nova import compute
|
from nova import compute
|
||||||
|
from nova.compute import instance_types
|
||||||
|
from nova.compute import manager as compute_manager
|
||||||
|
from nova.compute import power_state
|
||||||
from nova import context
|
from nova import context
|
||||||
from nova import db
|
from nova import db
|
||||||
|
from nova.db.sqlalchemy import models
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
|
import nova.image.fake
|
||||||
from nova import log as logging
|
from nova import log as logging
|
||||||
from nova import rpc
|
from nova import rpc
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova import utils
|
from nova import utils
|
||||||
from nova.auth import manager
|
|
||||||
from nova.compute import instance_types
|
|
||||||
from nova.compute import manager as compute_manager
|
|
||||||
from nova.compute import power_state
|
|
||||||
from nova.db.sqlalchemy import models
|
|
||||||
from nova.image import local
|
|
||||||
|
|
||||||
LOG = logging.getLogger('nova.tests.compute')
|
LOG = logging.getLogger('nova.tests.compute')
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
@@ -73,7 +73,7 @@ class ComputeTestCase(test.TestCase):
|
|||||||
def fake_show(meh, context, id):
|
def fake_show(meh, context, id):
|
||||||
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}}
|
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}}
|
||||||
|
|
||||||
self.stubs.Set(local.LocalImageService, 'show', fake_show)
|
self.stubs.Set(nova.image.fake._FakeImageService, 'show', fake_show)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.manager.delete_user(self.user)
|
self.manager.delete_user(self.user)
|
||||||
|
|||||||
Reference in New Issue
Block a user