This change set adds the ability to create new servers with an href that points to a server image on any glance server (not only the default one configured). This means you can create a server with imageRef = http://glance1:9292/images/3 and then also create one with imageRef = http://glance2:9292/images/1. Using the old way of passing in an image_id still works as well, and will use the default configured glance server (imageRef = 3 for instance).

We have tested pretty thoroughly with libvirt and xen.

All tests pass, and we have done full end-to-end testing manually to verify that server creation/deletion is working.
This commit is contained in:
Dan Prince 2011-06-03 02:36:49 +00:00 committed by Tarmac
commit 0fd5e0ca8b
35 changed files with 398 additions and 218 deletions

View File

@ -78,6 +78,7 @@ from nova import crypto
from nova import db
from nova import exception
from nova import flags
from nova import image
from nova import log as logging
from nova import quota
from nova import rpc
@ -936,7 +937,7 @@ class ImageCommands(object):
"""Methods for dealing with a cloud in an odd state"""
def __init__(self, *args, **kwargs):
self.image_service = utils.import_object(FLAGS.image_service)
self.image_service = image.get_default_image_service()
def _register(self, container_format, disk_format,
path, owner, name=None, is_public='T',

View File

@ -159,7 +159,7 @@ class CloudController(object):
floating_ip = db.instance_get_floating_address(ctxt,
instance_ref['id'])
ec2_id = ec2utils.id_to_ec2_id(instance_ref['id'])
image_ec2_id = self.image_ec2_id(instance_ref['image_id'])
image_ec2_id = self.image_ec2_id(instance_ref['image_ref'])
data = {
'user-data': base64.b64decode(instance_ref['user_data']),
'meta-data': {
@ -774,13 +774,13 @@ class CloudController(object):
instances = self.compute_api.get_all(context, **kwargs)
for instance in instances:
if not context.is_admin:
if instance['image_id'] == str(FLAGS.vpn_image_id):
if instance['image_ref'] == str(FLAGS.vpn_image_id):
continue
i = {}
instance_id = instance['id']
ec2_id = ec2utils.id_to_ec2_id(instance_id)
i['instanceId'] = ec2_id
i['imageId'] = self.image_ec2_id(instance['image_id'])
i['imageId'] = self.image_ec2_id(instance['image_ref'])
i['instanceState'] = {
'code': instance['state'],
'name': instance['state_description']}
@ -899,7 +899,7 @@ class CloudController(object):
instances = self.compute_api.create(context,
instance_type=instance_types.get_instance_type_by_name(
kwargs.get('instance_type', None)),
image_id=self._get_image(context, kwargs['image_id'])['id'],
image_href=self._get_image(context, kwargs['image_id'])['id'],
min_count=int(kwargs.get('min_count', max_count)),
max_count=max_count,
kernel_id=kwargs.get('kernel_id'),
@ -975,7 +975,12 @@ class CloudController(object):
def image_ec2_id(image_id, image_type='ami'):
"""Returns image ec2_id using id and three letter type."""
template = image_type + '-%08x'
return ec2utils.id_to_ec2_id(int(image_id), template=template)
try:
return ec2utils.id_to_ec2_id(int(image_id), template=template)
except ValueError:
#TODO(wwolf): once we have ec2_id -> glance_id mapping
# in place, this wont be necessary
return "ami-00000000"
def _get_image(self, context, ec2_id):
try:

View File

@ -99,34 +99,6 @@ def limited_by_marker(items, request, max_limit=FLAGS.osapi_max_limit):
return items[start_index:range_end]
def get_image_id_from_image_hash(image_service, context, image_hash):
"""Given an Image ID Hash, return an objectstore Image ID.
image_service - reference to objectstore compatible image service.
context - security context for image service requests.
image_hash - hash of the image ID.
"""
# FIX(sandy): This is terribly inefficient. It pulls all images
# from objectstore in order to find the match. ObjectStore
# should have a numeric counterpart to the string ID.
try:
items = image_service.detail(context)
except NotImplementedError:
items = image_service.index(context)
for image in items:
image_id = image['id']
try:
if abs(hash(image_id)) == int(image_hash):
return image_id
except ValueError:
msg = _("Requested image_id has wrong format: %s,"
"should have numerical format") % image_id
LOG.error(msg)
raise Exception(msg)
raise exception.ImageNotFound(image_id=image_hash)
def get_id_from_href(href):
"""Return the id portion of a url as an int.

View File

@ -18,6 +18,7 @@
from webob import exc
from nova import flags
from nova import image
from nova import quota
from nova import utils
from nova.api.openstack import faults
@ -31,7 +32,7 @@ class Controller(object):
"""The image metadata API controller for the Openstack API"""
def __init__(self):
self.image_service = utils.import_object(FLAGS.image_service)
self.image_service = image.get_default_image_service()
def _get_metadata(self, context, image_id, image=None):
if not image:

View File

@ -18,6 +18,7 @@ import webob.exc
from nova import compute
from nova import exception
from nova import flags
import nova.image
from nova import log
from nova import utils
from nova.api.openstack import common
@ -40,11 +41,11 @@ class Controller(object):
:param compute_service: `nova.compute.api:API`
:param image_service: `nova.image.service:BaseImageService`
"""
_default_service = utils.import_object(flags.FLAGS.image_service)
"""
self._compute_service = compute_service or compute.API()
self._image_service = image_service or _default_service
self._image_service = image_service or \
nova.image.get_default_image_service()
def index(self, req):
"""Return an index listing of images available to the request.
@ -88,22 +89,16 @@ class Controller(object):
"""Return detailed information about a specific image.
:param req: `wsgi.Request` object
:param id: Image identifier (integer)
:param id: Image identifier
"""
context = req.environ['nova.context']
try:
image_id = int(id)
except ValueError:
image = self._image_service.show(context, id)
except (exception.NotFound, exception.InvalidImageRef):
explanation = _("Image not found.")
raise faults.Fault(webob.exc.HTTPNotFound(explanation=explanation))
try:
image = self._image_service.show(context, image_id)
except exception.NotFound:
explanation = _("Image '%d' not found.") % (image_id)
raise faults.Fault(webob.exc.HTTPNotFound(explanation=explanation))
return dict(image=self.get_builder(req).build(image, detail=True))
def delete(self, req, id):
@ -112,9 +107,8 @@ class Controller(object):
:param req: `wsgi.Request` object
:param id: Image identifier (integer)
"""
image_id = id
context = req.environ['nova.context']
self._image_service.delete(context, image_id)
self._image_service.delete(context, id)
return webob.exc.HTTPNoContent()
def create(self, req, body):

View File

@ -22,6 +22,7 @@ from xml.dom import minidom
from nova import compute
from nova import exception
from nova import flags
import nova.image
from nova import log as logging
from nova import quota
from nova import utils
@ -51,13 +52,21 @@ class Controller(object):
def index(self, req):
""" Returns a list of server names and ids for a given user """
return self._items(req, is_detail=False)
try:
servers = self._items(req, is_detail=False)
except exception.Invalid as err:
return exc.HTTPBadRequest(str(err))
return servers
def detail(self, req):
""" Returns a list of server details for a given user """
return self._items(req, is_detail=True)
try:
servers = self._items(req, is_detail=True)
except exception.Invalid as err:
return exc.HTTPBadRequest(str(err))
return servers
def _image_id_from_req_data(self, data):
def _image_ref_from_req_data(self, data):
raise NotImplementedError()
def _flavor_id_from_req_data(self, data):
@ -121,18 +130,19 @@ class Controller(object):
key_name = key_pair['name']
key_data = key_pair['public_key']
requested_image_id = self._image_id_from_req_data(body)
image_href = self._image_ref_from_req_data(body)
try:
image_id = common.get_image_id_from_image_hash(self._image_service,
context, requested_image_id)
image_service, image_id = nova.image.get_image_service(image_href)
kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image(
req, image_service, image_id)
images = set([str(x['id']) for x in image_service.index(context)])
assert str(image_id) in images
except:
msg = _("Can not find requested image")
msg = _("Cannot find requested image %s") % image_href
return faults.Fault(exc.HTTPBadRequest(msg))
kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image(
req, image_id)
personality = body['server'].get('personality')
injected_files = []
if personality:
injected_files = self._get_injected_files(personality)
@ -153,7 +163,7 @@ class Controller(object):
(inst,) = self.compute_api.create(
context,
inst_type,
image_id,
image_href,
kernel_id=kernel_id,
ramdisk_id=ramdisk_id,
display_name=name,
@ -165,9 +175,12 @@ class Controller(object):
admin_password=password)
except quota.QuotaError as error:
self._handle_quota_error(error)
except exception.ImageNotFound as error:
msg = _("Can not find requested image")
return faults.Fault(exc.HTTPBadRequest(msg))
inst['instance_type'] = inst_type
inst['image_id'] = requested_image_id
inst['image_ref'] = image_href
builder = self._get_view_builder(req)
server = builder.build(inst, is_detail=True)
@ -505,17 +518,15 @@ class Controller(object):
error=item.error))
return dict(actions=actions)
def _get_kernel_ramdisk_from_image(self, req, image_id):
def _get_kernel_ramdisk_from_image(self, req, image_service, image_id):
"""Fetch an image from the ImageService, then if present, return the
associated kernel and ramdisk image IDs.
"""
context = req.environ['nova.context']
image_meta = self._image_service.show(context, image_id)
image_meta = image_service.show(context, image_id)
# NOTE(sirp): extracted to a separate method to aid unit-testing, the
# new method doesn't need a request obj or an ImageService stub
kernel_id, ramdisk_id = self._do_get_kernel_ramdisk_from_image(
image_meta)
return kernel_id, ramdisk_id
return self._do_get_kernel_ramdisk_from_image(image_meta)
@staticmethod
def _do_get_kernel_ramdisk_from_image(image_meta):
@ -546,7 +557,7 @@ class Controller(object):
class ControllerV10(Controller):
def _image_id_from_req_data(self, data):
def _image_ref_from_req_data(self, data):
return data['server']['imageId']
def _flavor_id_from_req_data(self, data):
@ -604,9 +615,8 @@ class ControllerV10(Controller):
class ControllerV11(Controller):
def _image_id_from_req_data(self, data):
href = data['server']['imageRef']
return common.get_id_from_href(href)
def _image_ref_from_req_data(self, data):
return data['server']['imageRef']
def _flavor_id_from_req_data(self, data):
href = data['server']['flavorRef']
@ -686,13 +696,12 @@ class ControllerV11(Controller):
instance_id = int(instance_id)
try:
image_ref = info["rebuild"]["imageRef"]
image_href = info["rebuild"]["imageRef"]
except (KeyError, TypeError):
msg = _("Could not parse imageRef from request.")
LOG.debug(msg)
return faults.Fault(exc.HTTPBadRequest(explanation=msg))
image_id = common.get_id_from_href(image_ref)
personalities = info["rebuild"].get("personality", [])
metadata = info["rebuild"].get("metadata")
name = info["rebuild"].get("name")
@ -702,7 +711,7 @@ class ControllerV11(Controller):
self._decode_personalities(personalities)
try:
self.compute_api.rebuild(context, instance_id, image_id, name,
self.compute_api.rebuild(context, instance_id, image_href, name,
metadata, personalities)
except exception.BuildInProgress:
msg = _("Instance %d is currently being rebuilt.") % instance_id

View File

@ -18,6 +18,7 @@
import hashlib
import os
from nova import exception
from nova.compute import power_state
import nova.compute
import nova.context
@ -112,8 +113,11 @@ class ViewBuilderV10(ViewBuilder):
"""Model an Openstack API V1.0 server response."""
def _build_image(self, response, inst):
if 'image_id' in dict(inst):
response['imageId'] = inst['image_id']
if 'image_ref' in dict(inst):
image_ref = inst['image_ref']
if str(image_ref).startswith('http'):
raise exception.ListingImageRefsNotSupported()
response['imageId'] = int(image_ref)
def _build_flavor(self, response, inst):
if 'instance_type' in dict(inst):
@ -130,9 +134,11 @@ class ViewBuilderV11(ViewBuilder):
self.base_url = base_url
def _build_image(self, response, inst):
if "image_id" in dict(inst):
image_id = inst.get("image_id")
response["imageRef"] = self.image_builder.generate_href(image_id)
if 'image_ref' in dict(inst):
image_href = inst['image_ref']
if str(image_href).isdigit():
image_href = int(image_href)
response['imageRef'] = image_href
def _build_flavor(self, response, inst):
if "instance_type" in dict(inst):

View File

@ -26,6 +26,7 @@ import time
from nova import db
from nova import exception
from nova import flags
import nova.image
from nova import log as logging
from nova import network
from nova import quota
@ -58,9 +59,9 @@ class API(base.Base):
def __init__(self, image_service=None, network_api=None,
volume_api=None, hostname_factory=generate_default_hostname,
**kwargs):
if not image_service:
image_service = utils.import_object(FLAGS.image_service)
self.image_service = image_service
self.image_service = image_service or \
nova.image.get_default_image_service()
if not network_api:
network_api = network.API()
self.network_api = network_api
@ -129,7 +130,7 @@ class API(base.Base):
raise quota.QuotaError(msg, "MetadataLimitExceeded")
def create(self, context, instance_type,
image_id, kernel_id=None, ramdisk_id=None,
image_href, kernel_id=None, ramdisk_id=None,
min_count=1, max_count=1,
display_name='', display_description='',
key_name=None, key_data=None, security_group='default',
@ -160,7 +161,8 @@ class API(base.Base):
self._check_metadata_properties_quota(context, metadata)
self._check_injected_file_quota(context, injected_files)
image = self.image_service.show(context, image_id)
(image_service, image_id) = nova.image.get_image_service(image_href)
image = image_service.show(context, image_id)
os_type = None
if 'properties' in image and 'os_type' in image['properties']:
@ -180,9 +182,9 @@ class API(base.Base):
logging.debug("Using Kernel=%s, Ramdisk=%s" %
(kernel_id, ramdisk_id))
if kernel_id:
self.image_service.show(context, kernel_id)
image_service.show(context, kernel_id)
if ramdisk_id:
self.image_service.show(context, ramdisk_id)
image_service.show(context, ramdisk_id)
if security_group is None:
security_group = ['default']
@ -203,7 +205,7 @@ class API(base.Base):
base_options = {
'reservation_id': utils.generate_uid('r'),
'image_id': image_id,
'image_ref': image_href,
'kernel_id': kernel_id or '',
'ramdisk_id': ramdisk_id or '',
'state': 0,
@ -529,8 +531,8 @@ class API(base.Base):
"""Reboot the given instance."""
self._cast_compute_message('reboot_instance', context, instance_id)
def rebuild(self, context, instance_id, image_id, name=None, metadata=None,
files_to_inject=None):
def rebuild(self, context, instance_id, image_href, name=None,
metadata=None, files_to_inject=None):
"""Rebuild the given instance with the provided metadata."""
instance = db.api.instance_get(context, instance_id)
@ -550,7 +552,7 @@ class API(base.Base):
self.db.instance_update(context, instance_id, values)
rebuild_params = {
"image_id": image_id,
"image_ref": image_href,
"injected_files": files_to_inject,
}

View File

@ -162,9 +162,9 @@ class ComputeManager(manager.SchedulerDependentManager):
data = {'launched_at': launched_at or datetime.datetime.utcnow()}
self.db.instance_update(context, instance_id, data)
def _update_image_id(self, context, instance_id, image_id):
def _update_image_ref(self, context, instance_id, image_ref):
"""Update the image_id for the given instance."""
data = {'image_id': image_id}
data = {'image_ref': image_ref}
self.db.instance_update(context, instance_id, data)
def get_console_topic(self, context, **kwargs):
@ -235,7 +235,7 @@ class ComputeManager(manager.SchedulerDependentManager):
power_state.NOSTATE,
'networking')
is_vpn = instance_ref['image_id'] == str(FLAGS.vpn_image_id)
is_vpn = instance_ref['image_ref'] == str(FLAGS.vpn_image_id)
# NOTE(vish): This could be a cast because we don't do anything
# with the address currently, but I'm leaving it as
# a call to ensure that network setup completes. We
@ -339,7 +339,7 @@ class ComputeManager(manager.SchedulerDependentManager):
:param context: `nova.RequestContext` object
:param instance_id: Instance identifier (integer)
:param image_id: Image identifier (integer)
:param image_ref: Image identifier (href or integer)
"""
context = context.elevated()
@ -349,11 +349,12 @@ class ComputeManager(manager.SchedulerDependentManager):
self._update_state(context, instance_id, power_state.BUILDING)
self.driver.destroy(instance_ref)
instance_ref.image_id = kwargs.get('image_id')
image_ref = kwargs.get('image_ref')
instance_ref.image_ref = image_ref
instance_ref.injected_files = kwargs.get('injected_files', [])
self.driver.spawn(instance_ref)
self._update_image_id(context, instance_id, image_id)
self._update_image_ref(context, instance_id, image_ref)
self._update_launched_at(context, instance_id)
self._update_state(context, instance_id)

View File

@ -956,7 +956,7 @@ def instance_get_project_vpn(context, project_id):
options(joinedload('security_groups')).\
options(joinedload('instance_type')).\
filter_by(project_id=project_id).\
filter_by(image_id=str(FLAGS.vpn_image_id)).\
filter_by(image_ref=str(FLAGS.vpn_image_id)).\
filter_by(deleted=can_read_deleted(context)).\
first()

View File

@ -0,0 +1,40 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
#
# 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.
from sqlalchemy import Column, Integer, MetaData, String, Table
meta = MetaData()
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine;
# bind migrate_engine to your metadata
meta.bind = migrate_engine
instances = Table('instances', meta, autoload=True,
autoload_with=migrate_engine)
image_id_column = instances.c.image_id
image_id_column.alter(name='image_ref')
def downgrade(migrate_engine):
meta.bind = migrate_engine
instances = Table('instances', meta, autoload=True,
autoload_with=migrate_engine)
image_ref_column = instances.c.image_ref
image_ref_column.alter(name='image_id')

View File

@ -184,11 +184,11 @@ class Instance(BASE, NovaBase):
def project(self):
return auth.manager.AuthManager().get_project(self.project_id)
image_id = Column(String(255))
image_ref = Column(String(255))
kernel_id = Column(String(255))
ramdisk_id = Column(String(255))
# image_id = Column(Integer, ForeignKey('images.id'), nullable=True)
# image_ref = Column(Integer, ForeignKey('images.id'), nullable=True)
# kernel_id = Column(Integer, ForeignKey('images.id'), nullable=True)
# ramdisk_id = Column(Integer, ForeignKey('images.id'), nullable=True)
# ramdisk = relationship(Ramdisk, backref=backref('instances', order_by=id))

View File

@ -291,6 +291,15 @@ class DiskNotFound(NotFound):
message = _("No disk at %(location)s")
class InvalidImageRef(Invalid):
message = _("Invalid image href %(image_href)s.")
class ListingImageRefsNotSupported(Invalid):
message = _("Some images have been stored via hrefs."
+ " This version of the api does not support displaying image hrefs.")
class ImageNotFound(NotFound):
message = _("Image %(image_id)s could not be found.")

View File

@ -0,0 +1,93 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2011 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.
from urlparse import urlparse
import nova
from nova import exception
from nova import utils
from nova import flags
FLAGS = flags.FLAGS
GlanceClient = utils.import_class('glance.client.Client')
def _parse_image_ref(image_href):
"""Parse an image href into composite parts.
:param image_href: href of an image
:returns: a tuple of the form (image_id, host, port)
"""
o = urlparse(image_href)
port = o.port or 80
host = o.netloc.split(':', 1)[0]
image_id = int(o.path.split('/')[-1])
return (image_id, host, port)
def get_default_image_service():
ImageService = utils.import_class(FLAGS.image_service)
return ImageService()
def get_glance_client(image_href):
"""Get the correct glance client and id for the given image_href.
The image_href param can be an href of the form
http://myglanceserver:9292/images/42, or just an int such as 42. If the
image_href is an int, then flags are used to create the default
glance client.
:param image_href: image ref/id for an image
:returns: a tuple of the form (glance_client, image_id)
"""
image_href = image_href or 0
if str(image_href).isdigit():
glance_client = GlanceClient(FLAGS.glance_host, FLAGS.glance_port)
return (glance_client, int(image_href))
try:
(image_id, host, port) = _parse_image_ref(image_href)
except:
raise exception.InvalidImageRef(image_href=image_href)
glance_client = GlanceClient(host, port)
return (glance_client, image_id)
def get_image_service(image_href):
"""Get the proper image_service and id for the given image_href.
The image_href param can be an href of the form
http://myglanceserver:9292/images/42, or just an int such as 42. If the
image_href is an int, then the default image service is returned.
:param image_href: image ref/id for an image
:returns: a tuple of the form (image_service, image_id)
"""
image_href = image_href or 0
if str(image_href).isdigit():
return (get_default_image_service(), int(image_href))
(glance_client, image_id) = get_glance_client(image_href)
image_service = nova.image.glance.GlanceImageService(glance_client)
return (image_service, image_id)

View File

@ -41,7 +41,7 @@ class _FakeImageService(service.BaseImageService):
# NOTE(justinsb): The OpenStack API can't upload an image?
# So, make sure we've got one..
timestamp = datetime.datetime(2011, 01, 01, 01, 02, 03)
image = {'id': '123456',
image1 = {'id': '123456',
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
@ -51,7 +51,52 @@ class _FakeImageService(service.BaseImageService):
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel,
'architecture': 'x86_64'}}
self.create(None, image)
image2 = {'id': 'fake',
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
'status': 'active',
'container_format': 'ami',
'disk_format': 'raw',
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel}}
image3 = {'id': '2',
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
'status': 'active',
'container_format': 'ami',
'disk_format': 'raw',
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel}}
image4 = {'id': '1',
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
'status': 'active',
'container_format': 'ami',
'disk_format': 'raw',
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel}}
image5 = {'id': '3',
'name': 'fakeimage123456',
'created_at': timestamp,
'updated_at': timestamp,
'status': 'active',
'container_format': 'ami',
'disk_format': 'raw',
'properties': {'kernel_id': FLAGS.null_kernel,
'ramdisk_id': FLAGS.null_kernel}}
self.create(None, image1)
self.create(None, image2)
self.create(None, image3)
self.create(None, image4)
self.create(None, image5)
super(_FakeImageService, self).__init__()
def index(self, context, filters=None):
@ -68,8 +113,7 @@ class _FakeImageService(service.BaseImageService):
Returns a dict containing image data for the given opaque image id.
"""
image_id = int(image_id)
image = self.images.get(image_id)
image = self.images.get(str(image_id))
if image:
return copy.deepcopy(image)
LOG.warn('Unable to find image id %s. Have images: %s',
@ -83,9 +127,10 @@ class _FakeImageService(service.BaseImageService):
"""
try:
image_id = int(metadata['id'])
image_id = metadata['id']
except KeyError:
image_id = random.randint(0, 2 ** 31 - 1)
image_id = str(image_id)
if self.images.get(image_id):
raise exception.Duplicate()
@ -100,7 +145,6 @@ class _FakeImageService(service.BaseImageService):
:raises: ImageNotFound if the image does not exist.
"""
image_id = int(image_id)
if not self.images.get(image_id):
raise exception.ImageNotFound(image_id=image_id)
self.images[image_id] = copy.deepcopy(metadata)
@ -111,7 +155,6 @@ class _FakeImageService(service.BaseImageService):
:raises: ImageNotFound if the image does not exist.
"""
image_id = int(image_id)
removed = self.images.pop(image_id, None)
if not removed:
raise exception.ImageNotFound(image_id=image_id)

View File

@ -31,6 +31,7 @@ import eventlet
from nova import crypto
from nova import exception
from nova import flags
from nova import image
from nova import log as logging
from nova import utils
from nova.auth import manager
@ -48,9 +49,7 @@ class S3ImageService(service.BaseImageService):
"""Wraps an existing image service to support s3 based register."""
def __init__(self, service=None, *args, **kwargs):
if service is None:
service = utils.import_object(FLAGS.image_service)
self.service = service
self.service = service or image.get_default_image_service()
self.service.__init__(*args, **kwargs)
def create(self, context, metadata, data=None):

View File

@ -38,6 +38,7 @@ from nova.api.openstack import auth
from nova.api.openstack import versions
from nova.api.openstack import limits
from nova.auth.manager import User, Project
import nova.image.fake
from nova.image import glance
from nova.image import local
from nova.image import service
@ -104,10 +105,12 @@ def stub_out_key_pair_funcs(stubs, have_key_pair=True):
def stub_out_image_service(stubs):
def fake_image_show(meh, context, id):
return dict(kernelId=1, ramdiskId=1)
stubs.Set(local.LocalImageService, 'show', fake_image_show)
def fake_get_image_service(image_href):
image_id = int(str(image_href).split('/')[-1])
return (nova.image.fake.FakeImageService(), image_id)
stubs.Set(nova.image, 'get_image_service', fake_get_image_service)
stubs.Set(nova.image, 'get_default_image_service',
lambda: nova.image.fake.FakeImageService())
def stub_out_auth(stubs):
@ -208,7 +211,7 @@ def stub_out_glance(stubs, initial_fixtures=None):
def _find_image(self, image_id):
for f in self.fixtures:
if f['id'] == image_id:
if str(f['id']) == str(image_id):
return f
return None

View File

@ -37,6 +37,7 @@ from nova.compute import power_state
import nova.db.api
from nova.db.sqlalchemy.models import Instance
from nova.db.sqlalchemy.models import InstanceMetadata
import nova.image.fake
import nova.rpc
from nova.tests.api.openstack import common
from nova.tests.api.openstack import fakes
@ -97,7 +98,7 @@ def stub_instance(id, user_id=1, private_address=None, public_addresses=None,
"admin_pass": "",
"user_id": user_id,
"project_id": "",
"image_id": "10",
"image_ref": "10",
"kernel_id": "",
"ramdisk_id": "",
"launch_index": 0,
@ -484,8 +485,6 @@ class ServersTest(test.TestCase):
fake_method)
self.stubs.Set(nova.api.openstack.servers.Controller,
"_get_kernel_ramdisk_from_image", kernel_ramdisk_mapping)
self.stubs.Set(nova.api.openstack.common,
"get_image_id_from_image_hash", image_id_from_hash)
self.stubs.Set(nova.compute.api.API, "_find_host", find_host)
def _test_create_instance_helper(self):
@ -588,12 +587,12 @@ class ServersTest(test.TestCase):
def test_create_instance_v1_1(self):
self._setup_for_create_instance()
image_ref = 'http://localhost/v1.1/images/2'
image_href = 'http://localhost/v1.1/images/2'
flavor_ref = 'http://localhost/v1.1/flavors/3'
body = {
'server': {
'name': 'server_test',
'imageRef': image_ref,
'imageRef': image_href,
'flavorRef': flavor_ref,
'metadata': {
'hello': 'world',
@ -615,16 +614,16 @@ class ServersTest(test.TestCase):
self.assertEqual('server_test', server['name'])
self.assertEqual(1, server['id'])
self.assertEqual(flavor_ref, server['flavorRef'])
self.assertEqual(image_ref, server['imageRef'])
self.assertEqual(image_href, server['imageRef'])
self.assertEqual(res.status_int, 200)
def test_create_instance_v1_1_bad_href(self):
self._setup_for_create_instance()
image_ref = 'http://localhost/v1.1/images/asdf'
image_href = 'http://localhost/v1.1/images/asdf'
flavor_ref = 'http://localhost/v1.1/flavors/3'
body = dict(server=dict(
name='server_test', imageRef=image_ref, flavorRef=flavor_ref,
name='server_test', imageRef=image_href, flavorRef=flavor_ref,
metadata={'hello': 'world', 'open': 'stack'},
personality={}))
req = webob.Request.blank('/v1.1/servers')
@ -637,13 +636,12 @@ class ServersTest(test.TestCase):
def test_create_instance_v1_1_local_href(self):
self._setup_for_create_instance()
image_ref = 'http://localhost/v1.1/images/2'
image_ref_local = '2'
image_id = 2
flavor_ref = 'http://localhost/v1.1/flavors/3'
body = {
'server': {
'name': 'server_test',
'imageRef': image_ref_local,
'imageRef': image_id,
'flavorRef': flavor_ref,
},
}
@ -658,7 +656,7 @@ class ServersTest(test.TestCase):
server = json.loads(res.body)['server']
self.assertEqual(1, server['id'])
self.assertEqual(flavor_ref, server['flavorRef'])
self.assertEqual(image_ref, server['imageRef'])
self.assertEqual(image_id, server['imageRef'])
self.assertEqual(res.status_int, 200)
def test_create_instance_with_admin_pass_v1_0(self):
@ -685,12 +683,12 @@ class ServersTest(test.TestCase):
def test_create_instance_with_admin_pass_v1_1(self):
self._setup_for_create_instance()
image_ref = 'http://localhost/v1.1/images/2'
image_href = 'http://localhost/v1.1/images/2'
flavor_ref = 'http://localhost/v1.1/flavors/3'
body = {
'server': {
'name': 'server_test',
'imageRef': image_ref,
'imageRef': image_href,
'flavorRef': flavor_ref,
'adminPass': 'testpass',
},
@ -707,12 +705,12 @@ class ServersTest(test.TestCase):
def test_create_instance_with_empty_admin_pass_v1_1(self):
self._setup_for_create_instance()
image_ref = 'http://localhost/v1.1/images/2'
image_href = 'http://localhost/v1.1/images/2'
flavor_ref = 'http://localhost/v1.1/flavors/3'
body = {
'server': {
'name': 'server_test',
'imageRef': image_ref,
'imageRef': image_href,
'flavorRef': flavor_ref,
'adminPass': '',
},
@ -861,7 +859,7 @@ class ServersTest(test.TestCase):
self.assertEqual(s['id'], i)
self.assertEqual(s['hostId'], '')
self.assertEqual(s['name'], 'server%d' % i)
self.assertEqual(s['imageId'], '10')
self.assertEqual(s['imageId'], 10)
self.assertEqual(s['flavorId'], 1)
self.assertEqual(s['status'], 'BUILD')
self.assertEqual(s['metadata']['seq'], str(i))
@ -875,7 +873,7 @@ class ServersTest(test.TestCase):
self.assertEqual(s['id'], i)
self.assertEqual(s['hostId'], '')
self.assertEqual(s['name'], 'server%d' % i)
self.assertEqual(s['imageRef'], 'http://localhost/v1.1/images/10')
self.assertEqual(s['imageRef'], 10)
self.assertEqual(s['flavorRef'], 'http://localhost/v1.1/flavors/1')
self.assertEqual(s['status'], 'BUILD')
self.assertEqual(s['metadata']['seq'], str(i))
@ -907,7 +905,7 @@ class ServersTest(test.TestCase):
self.assertEqual(s['id'], i)
self.assertEqual(s['hostId'], host_ids[i % 2])
self.assertEqual(s['name'], 'server%d' % i)
self.assertEqual(s['imageId'], '10')
self.assertEqual(s['imageId'], 10)
self.assertEqual(s['flavorId'], 1)
def test_server_pause(self):
@ -1680,7 +1678,7 @@ b25zLiINCg0KLVJpY2hhcmQgQmFjaA==""",
request = self.deserializer.deserialize(serial_request, 'create')
self.assertEqual(request, expected)
def test_request_xmlser_with_flavor_image_ref(self):
def test_request_xmlser_with_flavor_image_href(self):
serial_request = """
<server xmlns="http://docs.openstack.org/compute/api/v1.1"
name="new-server-test"
@ -1702,6 +1700,7 @@ class TestServerInstanceCreation(test.TestCase):
fakes.FakeAuthManager.auth_data = {}
fakes.FakeAuthDatabase.data = {}
fakes.stub_out_auth(self.stubs)
fakes.stub_out_image_service(self.stubs)
fakes.stub_out_key_pair_funcs(self.stubs)
self.allow_admin = FLAGS.allow_admin_api
@ -1736,8 +1735,6 @@ class TestServerInstanceCreation(test.TestCase):
self.stubs.Set(nova.compute, 'API', make_stub_method(compute_api))
self.stubs.Set(nova.api.openstack.servers.Controller,
'_get_kernel_ramdisk_from_image', make_stub_method((1, 1)))
self.stubs.Set(nova.api.openstack.common,
'get_image_id_from_image_hash', make_stub_method(2))
return compute_api
def _create_personality_request_dict(self, personality_files):

View File

@ -16,13 +16,14 @@
import StringIO
import glance.client
import nova.image
def stubout_glance_client(stubs, cls):
"""Stubs out glance.client.Client"""
stubs.Set(glance.client, 'Client',
lambda *args, **kwargs: cls(*args, **kwargs))
def stubout_glance_client(stubs):
def fake_get_glance_client(image_href):
image_id = int(str(image_href).split('/')[-1])
return (FakeGlance('foo'), image_id)
stubs.Set(nova.image, 'get_glance_client', fake_get_glance_client)
class FakeGlance(object):

View File

@ -27,6 +27,7 @@ from nova import flags
from nova import service
from nova import test # For the flags
from nova.auth import manager
import nova.image.glance
from nova.log import logging
from nova.tests.integrated.api import client
@ -151,6 +152,11 @@ class _IntegratedTestBase(test.TestCase):
f = self._get_flags()
self.flags(**f)
def fake_get_image_service(image_href):
image_id = int(str(image_href).split('/')[-1])
return (nova.image.fake.FakeImageService(), image_id)
self.stubs.Set(nova.image, 'get_image_service', fake_get_image_service)
# set up services
self.start_service('compute')
self.start_service('volume')
@ -199,19 +205,13 @@ class _IntegratedTestBase(test.TestCase):
LOG.debug("Image: %s" % image)
if 'imageRef' in image:
image_ref = image['imageRef']
image_href = image['imageRef']
else:
# NOTE(justinsb): The imageRef code hasn't yet landed
LOG.warning("imageRef not yet in images output")
image_ref = image['id']
# TODO(justinsb): This is FUBAR
image_ref = abs(hash(image_ref))
image_ref = 'http://fake.server/%s' % image_ref
image_href = image['id']
image_href = 'http://fake.server/%s' % image_href
# We now have a valid imageId
server['imageRef'] = image_ref
server['imageRef'] = image_href
# Set a valid flavorId
flavor = self.api.get_flavors()[0]

View File

@ -254,10 +254,10 @@ class CloudTestCase(test.TestCase):
def test_describe_instances(self):
"""Makes sure describe_instances works and filters results."""
inst1 = db.instance_create(self.context, {'reservation_id': 'a',
'image_id': 1,
'image_ref': 1,
'host': 'host1'})
inst2 = db.instance_create(self.context, {'reservation_id': 'a',
'image_id': 1,
'image_ref': 1,
'host': 'host2'})
comp1 = db.service_create(self.context, {'host': 'host1',
'availability_zone': 'zone1',
@ -447,7 +447,7 @@ class CloudTestCase(test.TestCase):
def test_terminate_instances(self):
inst1 = db.instance_create(self.context, {'reservation_id': 'a',
'image_id': 1,
'image_ref': 1,
'host': 'host1'})
terminate_instances = self.cloud.terminate_instances
# valid instance_id

View File

@ -84,7 +84,7 @@ class ComputeTestCase(test.TestCase):
def _create_instance(self, params={}):
"""Create a test instance"""
inst = {}
inst['image_id'] = 1
inst['image_ref'] = 1
inst['reservation_id'] = 'r-fakeres'
inst['launch_time'] = '10'
inst['user_id'] = self.user.id
@ -150,7 +150,7 @@ class ComputeTestCase(test.TestCase):
ref = self.compute_api.create(
self.context,
instance_type=instance_types.get_default_instance_type(),
image_id=None,
image_href=None,
security_group=['testgroup'])
try:
self.assertEqual(len(db.security_group_get_by_instance(
@ -168,7 +168,7 @@ class ComputeTestCase(test.TestCase):
ref = self.compute_api.create(
self.context,
instance_type=instance_types.get_default_instance_type(),
image_id=None,
image_href=None,
security_group=['testgroup'])
try:
db.instance_destroy(self.context, ref[0]['id'])
@ -184,7 +184,7 @@ class ComputeTestCase(test.TestCase):
ref = self.compute_api.create(
self.context,
instance_type=instance_types.get_default_instance_type(),
image_id=None,
image_href=None,
security_group=['testgroup'])
try:

View File

@ -161,7 +161,7 @@ class LibvirtConnTestCase(test.TestCase):
'vcpus': 2,
'project_id': 'fake',
'bridge': 'br101',
'image_id': '123456',
'image_ref': '123456',
'instance_type_id': '5'} # m1.small
def lazy_load_library_exists(self):

View File

@ -223,7 +223,7 @@ class QuotaTestCase(test.TestCase):
min_count=1,
max_count=1,
instance_type=inst_type,
image_id=1)
image_href=1)
for instance_id in instance_ids:
db.instance_destroy(self.context, instance_id)
@ -237,7 +237,7 @@ class QuotaTestCase(test.TestCase):
min_count=1,
max_count=1,
instance_type=inst_type,
image_id=1)
image_href=1)
for instance_id in instance_ids:
db.instance_destroy(self.context, instance_id)
@ -295,7 +295,7 @@ class QuotaTestCase(test.TestCase):
min_count=1,
max_count=1,
instance_type=inst_type,
image_id='fake',
image_href='fake',
metadata=metadata)
def test_default_allowed_injected_files(self):
@ -341,16 +341,18 @@ class QuotaTestCase(test.TestCase):
self.assertEqual(limit, 23456)
def _create_with_injected_files(self, files):
FLAGS.image_service = 'nova.image.fake.FakeImageService'
api = compute.API(image_service=self.StubImageService())
inst_type = instance_types.get_instance_type_by_name('m1.small')
api.create(self.context, min_count=1, max_count=1,
instance_type=inst_type, image_id='fake',
instance_type=inst_type, image_href='3',
injected_files=files)
def test_no_injected_files(self):
FLAGS.image_service = 'nova.image.fake.FakeImageService'
api = compute.API(image_service=self.StubImageService())
inst_type = instance_types.get_instance_type_by_name('m1.small')
api.create(self.context, instance_type=inst_type, image_id='fake')
api.create(self.context, instance_type=inst_type, image_href='3')
def test_max_injected_files(self):
files = []

View File

@ -55,8 +55,7 @@ class VMWareAPIVMTestCase(test.TestCase):
vmwareapi_fake.reset()
db_fakes.stub_out_db_instance_api(self.stubs)
stubs.set_stubs(self.stubs)
glance_stubs.stubout_glance_client(self.stubs,
glance_stubs.FakeGlance)
glance_stubs.stubout_glance_client(self.stubs)
self.conn = vmwareapi_conn.get_connection(False)
def _create_instance_in_the_db(self):
@ -64,7 +63,7 @@ class VMWareAPIVMTestCase(test.TestCase):
'id': 1,
'project_id': self.project.id,
'user_id': self.user.id,
'image_id': "1",
'image_ref': "1",
'kernel_id': "1",
'ramdisk_id': "1",
'instance_type': 'm1.large',

View File

@ -79,7 +79,7 @@ class XenAPIVolumeTestCase(test.TestCase):
self.values = {'id': 1,
'project_id': 'fake',
'user_id': 'fake',
'image_id': 1,
'image_ref': 1,
'kernel_id': 2,
'ramdisk_id': 3,
'instance_type_id': '3', # m1.large
@ -193,8 +193,7 @@ class XenAPIVMTestCase(test.TestCase):
stubs.stubout_is_vdi_pv(self.stubs)
self.stubs.Set(VMOps, 'reset_network', reset_network)
stubs.stub_out_vm_methods(self.stubs)
glance_stubs.stubout_glance_client(self.stubs,
glance_stubs.FakeGlance)
glance_stubs.stubout_glance_client(self.stubs)
fake_utils.stub_out_utils_execute(self.stubs)
self.context = context.RequestContext('fake', 'fake', False)
self.conn = xenapi_conn.get_connection(False)
@ -207,7 +206,7 @@ class XenAPIVMTestCase(test.TestCase):
'id': id,
'project_id': proj,
'user_id': user,
'image_id': 1,
'image_ref': 1,
'kernel_id': 2,
'ramdisk_id': 3,
'instance_type_id': '3', # m1.large
@ -351,14 +350,14 @@ class XenAPIVMTestCase(test.TestCase):
self.assertEquals(self.vm['HVM_boot_params'], {})
self.assertEquals(self.vm['HVM_boot_policy'], '')
def _test_spawn(self, image_id, kernel_id, ramdisk_id,
def _test_spawn(self, image_ref, kernel_id, ramdisk_id,
instance_type_id="3", os_type="linux",
instance_id=1, check_injection=False):
stubs.stubout_loopingcall_start(self.stubs)
values = {'id': instance_id,
'project_id': self.project.id,
'user_id': self.user.id,
'image_id': image_id,
'image_ref': image_ref,
'kernel_id': kernel_id,
'ramdisk_id': ramdisk_id,
'instance_type_id': instance_type_id,
@ -567,7 +566,7 @@ class XenAPIVMTestCase(test.TestCase):
'id': 1,
'project_id': self.project.id,
'user_id': self.user.id,
'image_id': 1,
'image_ref': 1,
'kernel_id': 2,
'ramdisk_id': 3,
'instance_type_id': '3', # m1.large
@ -641,7 +640,7 @@ class XenAPIMigrateInstance(test.TestCase):
self.values = {'id': 1,
'project_id': self.project.id,
'user_id': self.user.id,
'image_id': 1,
'image_ref': 1,
'kernel_id': None,
'ramdisk_id': None,
'local_gb': 5,
@ -652,8 +651,7 @@ class XenAPIMigrateInstance(test.TestCase):
fake_utils.stub_out_utils_execute(self.stubs)
stubs.stub_out_migration_methods(self.stubs)
stubs.stubout_get_this_vm_uuid(self.stubs)
glance_stubs.stubout_glance_client(self.stubs,
glance_stubs.FakeGlance)
glance_stubs.stubout_glance_client(self.stubs)
def tearDown(self):
super(XenAPIMigrateInstance, self).tearDown()
@ -679,8 +677,7 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
"""Unit tests for code that detects the ImageType."""
def setUp(self):
super(XenAPIDetermineDiskImageTestCase, self).setUp()
glance_stubs.stubout_glance_client(self.stubs,
glance_stubs.FakeGlance)
glance_stubs.stubout_glance_client(self.stubs)
class FakeInstance(object):
pass
@ -697,7 +694,7 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
def test_instance_disk(self):
"""If a kernel is specified, the image type is DISK (aka machine)."""
FLAGS.xenapi_image_service = 'objectstore'
self.fake_instance.image_id = glance_stubs.FakeGlance.IMAGE_MACHINE
self.fake_instance.image_ref = glance_stubs.FakeGlance.IMAGE_MACHINE
self.fake_instance.kernel_id = glance_stubs.FakeGlance.IMAGE_KERNEL
self.assert_disk_type(vm_utils.ImageType.DISK)
@ -707,7 +704,7 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
DISK_RAW is assumed.
"""
FLAGS.xenapi_image_service = 'objectstore'
self.fake_instance.image_id = glance_stubs.FakeGlance.IMAGE_RAW
self.fake_instance.image_ref = glance_stubs.FakeGlance.IMAGE_RAW
self.fake_instance.kernel_id = None
self.assert_disk_type(vm_utils.ImageType.DISK_RAW)
@ -717,7 +714,7 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
this case will be 'raw'.
"""
FLAGS.xenapi_image_service = 'glance'
self.fake_instance.image_id = glance_stubs.FakeGlance.IMAGE_RAW
self.fake_instance.image_ref = glance_stubs.FakeGlance.IMAGE_RAW
self.fake_instance.kernel_id = None
self.assert_disk_type(vm_utils.ImageType.DISK_RAW)
@ -727,7 +724,7 @@ class XenAPIDetermineDiskImageTestCase(test.TestCase):
this case will be 'vhd'.
"""
FLAGS.xenapi_image_service = 'glance'
self.fake_instance.image_id = glance_stubs.FakeGlance.IMAGE_VHD
self.fake_instance.image_ref = glance_stubs.FakeGlance.IMAGE_VHD
self.fake_instance.kernel_id = None
self.assert_disk_type(vm_utils.ImageType.DISK_VHD)

View File

@ -61,7 +61,7 @@ def stub_out_db_instance_api(stubs):
'name': values['name'],
'id': values['id'],
'reservation_id': utils.generate_uid('r'),
'image_id': values['image_id'],
'image_ref': values['image_ref'],
'kernel_id': values['kernel_id'],
'ramdisk_id': values['ramdisk_id'],
'state_description': 'scheduling',

View File

@ -151,7 +151,7 @@ class HyperVConnection(driver.ComputeDriver):
base_vhd_filename = os.path.join(FLAGS.instances_path,
instance.name)
vhdfile = "%s.vhd" % (base_vhd_filename)
images.fetch(instance['image_id'], vhdfile, user, project)
images.fetch(instance['image_ref'], vhdfile, user, project)
try:
self._create_vm(instance)

View File

@ -23,6 +23,7 @@ Handling of VM disk images.
from nova import context
from nova import flags
import nova.image
from nova import log as logging
from nova import utils
@ -31,12 +32,12 @@ FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.virt.images')
def fetch(image_id, path, _user, _project):
def fetch(image_href, path, _user, _project):
# TODO(vish): Improve context handling and add owner and auth data
# when it is added to glance. Right now there is no
# auth checking in glance, so we assume that access was
# checked before we got here.
image_service = utils.import_object(FLAGS.image_service)
(image_service, image_id) = nova.image.get_image_service(image_href)
with open(path, "wb") as image_file:
elevated = context.get_admin_context()
metadata = image_service.get(elevated, image_id, image_file)

View File

@ -36,6 +36,7 @@ Supports KVM, LXC, QEMU, UML, and XEN.
"""
import hashlib
import multiprocessing
import os
import random
@ -57,6 +58,7 @@ from nova import context
from nova import db
from nova import exception
from nova import flags
import nova.image
from nova import log as logging
from nova import utils
from nova import vnc
@ -378,7 +380,7 @@ class LibvirtConnection(driver.ComputeDriver):
virt_dom.detachDevice(xml)
@exception.wrap_exception
def snapshot(self, instance, image_id):
def snapshot(self, instance, image_href):
"""Create snapshot from a running VM instance.
This command only works with qemu 0.14+, the qemu_img flag is
@ -386,12 +388,15 @@ class LibvirtConnection(driver.ComputeDriver):
to support this command.
"""
image_service = utils.import_object(FLAGS.image_service)
virt_dom = self._lookup_by_name(instance['name'])
elevated = context.get_admin_context()
base = image_service.show(elevated, instance['image_id'])
snapshot = image_service.show(elevated, image_id)
(image_service, image_id) = nova.image.get_image_service(
instance['image_ref'])
base = image_service.show(elevated, image_id)
(snapshot_image_service, snapshot_image_id) = \
nova.image.get_image_service(image_href)
snapshot = snapshot_image_service.show(elevated, snapshot_image_id)
metadata = {'disk_format': base['disk_format'],
'container_format': base['container_format'],
@ -441,7 +446,7 @@ class LibvirtConnection(driver.ComputeDriver):
# Upload that image to the image service
with open(out_path) as image_file:
image_service.update(elevated,
image_id,
image_href,
metadata,
image_file)
@ -787,7 +792,7 @@ class LibvirtConnection(driver.ComputeDriver):
project = manager.AuthManager().get_project(inst['project_id'])
if not disk_images:
disk_images = {'image_id': inst['image_id'],
disk_images = {'image_id': inst['image_ref'],
'kernel_id': inst['kernel_id'],
'ramdisk_id': inst['ramdisk_id']}
@ -808,7 +813,7 @@ class LibvirtConnection(driver.ComputeDriver):
user=user,
project=project)
root_fname = '%08x' % int(disk_images['image_id'])
root_fname = hashlib.sha1(disk_images['image_id']).hexdigest()
size = FLAGS.minimum_root_size
inst_type_id = inst['instance_type_id']
@ -883,7 +888,7 @@ class LibvirtConnection(driver.ComputeDriver):
if key or net:
inst_name = inst['name']
img_id = inst.image_id
img_id = inst.image_ref
if key:
LOG.info(_('instance %(inst_name)s: injecting key into'
' image %(img_id)s') % locals())

View File

@ -195,7 +195,7 @@ class NWFilterFirewall(FirewallDriver):
logging.info('ensuring static filters')
self._ensure_static_filters()
if instance['image_id'] == str(FLAGS.vpn_image_id):
if instance['image_ref'] == str(FLAGS.vpn_image_id):
base_filter = 'nova-vpn'
else:
base_filter = 'nova-base'
@ -336,7 +336,7 @@ class NWFilterFirewall(FirewallDriver):
def _create_network_filters(self, instance, network_info,
instance_secgroup_filter_name):
if instance['image_id'] == str(FLAGS.vpn_image_id):
if instance['image_ref'] == str(FLAGS.vpn_image_id):
base_filter = 'nova-vpn'
else:
base_filter = 'nova-base'

View File

@ -150,7 +150,7 @@ class VMWareVMOps(object):
"""
image_size, image_properties = \
vmware_images.get_vmdk_size_and_properties(
instance.image_id, instance)
instance.image_ref, instance)
vmdk_file_size_in_kb = int(image_size) / 1024
os_type = image_properties.get("vmware_ostype", "otherGuest")
adapter_type = image_properties.get("vmware_adaptertype",
@ -265,23 +265,23 @@ class VMWareVMOps(object):
def _fetch_image_on_esx_datastore():
"""Fetch image from Glance to ESX datastore."""
LOG.debug(_("Downloading image file data %(image_id)s to the ESX "
LOG.debug(_("Downloading image file data %(image_ref)s to the ESX "
"data store %(data_store_name)s") %
({'image_id': instance.image_id,
({'image_ref': instance.image_ref,
'data_store_name': data_store_name}))
# Upload the -flat.vmdk file whose meta-data file we just created
# above
vmware_images.fetch_image(
instance.image_id,
instance.image_ref,
instance,
host=self._session._host_ip,
data_center_name=self._get_datacenter_name_and_ref()[1],
datastore_name=data_store_name,
cookies=cookies,
file_path=flat_uploaded_vmdk_name)
LOG.debug(_("Downloaded image file data %(image_id)s to the ESX "
LOG.debug(_("Downloaded image file data %(image_ref)s to the ESX "
"data store %(data_store_name)s") %
({'image_id': instance.image_id,
({'image_ref': instance.image_ref,
'data_store_name': data_store_name}))
_fetch_image_on_esx_datastore()

View File

@ -18,10 +18,9 @@
Utility functions for Image transfer.
"""
from glance import client
from nova import exception
from nova import flags
import nova.image
from nova import log as logging
from nova.virt.vmwareapi import io_util
from nova.virt.vmwareapi import read_write_util
@ -117,8 +116,8 @@ def upload_image(image, instance, **kwargs):
def _get_glance_image(image, instance, **kwargs):
"""Download image from the glance image server."""
LOG.debug(_("Downloading image %s from glance image server") % image)
glance_client = client.Client(FLAGS.glance_host, FLAGS.glance_port)
metadata, read_iter = glance_client.get_image(image)
(glance_client, image_id) = nova.image.get_glance_client(image)
metadata, read_iter = glance_client.get_image(image_id)
read_file_handle = read_write_util.GlanceFileRead(read_iter)
file_size = int(metadata['size'])
write_file_handle = read_write_util.VMWareHTTPWriteFile(
@ -153,7 +152,7 @@ def _put_glance_image(image, instance, **kwargs):
kwargs.get("cookies"),
kwargs.get("file_path"))
file_size = read_file_handle.get_size()
glance_client = client.Client(FLAGS.glance_host, FLAGS.glance_port)
(glance_client, image_id) = nova.image.get_glance_client(image)
# The properties and other fields that we need to set for the image.
image_metadata = {"is_public": True,
"disk_format": "vmdk",
@ -165,7 +164,7 @@ def _put_glance_image(image, instance, **kwargs):
"vmware_image_version":
kwargs.get("image_version")}}
start_transfer(read_file_handle, file_size, glance_client=glance_client,
image_id=image, image_meta=image_metadata)
image_id=image_id, image_meta=image_metadata)
LOG.debug(_("Uploaded image %s to the Glance image server") % image)
@ -188,9 +187,8 @@ def get_vmdk_size_and_properties(image, instance):
LOG.debug(_("Getting image size for the image %s") % image)
if FLAGS.image_service == "nova.image.glance.GlanceImageService":
glance_client = client.Client(FLAGS.glance_host,
FLAGS.glance_port)
meta_data = glance_client.get_image_meta(image)
(glance_client, image_id) = nova.image.get_glance_client(image)
meta_data = glance_client.get_image_meta(image_id)
size, properties = meta_data["size"], meta_data["properties"]
elif FLAGS.image_service == "nova.image.s3.S3ImageService":
raise NotImplementedError

View File

@ -32,6 +32,7 @@ from xml.dom import minidom
import glance.client
from nova import exception
from nova import flags
import nova.image
from nova import log as logging
from nova import utils
from nova.auth.manager import AuthManager
@ -455,8 +456,8 @@ class VMHelper(HelperBase):
# DISK restores
sr_ref = safe_find_sr(session)
client = glance.client.Client(FLAGS.glance_host, FLAGS.glance_port)
meta, image_file = client.get_image(image)
glance_client, image_id = nova.image.get_glance_client(image)
meta, image_file = glance_client.get_image(image_id)
virtual_size = int(meta['size'])
vdi_size = virtual_size
LOG.debug(_("Size for image %(image)s:%(virtual_size)d") % locals())
@ -515,10 +516,10 @@ class VMHelper(HelperBase):
ImageType.DISK_RAW: 'DISK_RAW',
ImageType.DISK_VHD: 'DISK_VHD'}
disk_format = pretty_format[image_type]
image_id = instance.image_id
image_ref = instance.image_ref
instance_id = instance.id
LOG.debug(_("Detected %(disk_format)s format for image "
"%(image_id)s, instance %(instance_id)s") % locals())
"%(image_ref)s, instance %(instance_id)s") % locals())
def determine_from_glance():
glance_disk_format2nova_type = {
@ -527,8 +528,9 @@ class VMHelper(HelperBase):
'ari': ImageType.KERNEL_RAMDISK,
'raw': ImageType.DISK_RAW,
'vhd': ImageType.DISK_VHD}
client = glance.client.Client(FLAGS.glance_host, FLAGS.glance_port)
meta = client.get_image_meta(instance.image_id)
image_ref = instance.image_ref
glance_client, image_id = nova.image.get_glance_client(image_ref)
meta = glance_client.get_image_meta(image_id)
disk_format = meta['disk_format']
try:
return glance_disk_format2nova_type[disk_format]

View File

@ -111,7 +111,7 @@ class VMOps(object):
project = AuthManager().get_project(instance.project_id)
disk_image_type = VMHelper.determine_disk_image_type(instance)
vdis = VMHelper.fetch_image(self._session,
instance.id, instance.image_id, user, project,
instance.id, instance.image_ref, user, project,
disk_image_type)
return vdis