Add missing image to instance booted from volume

When booting an instance from a volume, the image_ref for
the instance will be None. And the API do not get the image
information for the instance also. So when we calling the
related API, we get "" for instance.image.

Change-Id: I3c35ab1d7c8bcec551fb5d67d0b44418266b32a4
Closes-bug: 1317880
This commit is contained in:
liyingjun
2014-06-24 19:20:50 +08:00
parent 277c69af20
commit c3191cf0ba
4 changed files with 76 additions and 1 deletions

View File

@@ -34,6 +34,7 @@ from nova import compute
from nova.compute import flavors
from nova import exception
from nova import objects
from nova.objects import instance as instance_obj
from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
from nova.openstack.common import strutils
@@ -599,6 +600,8 @@ class Controller(wsgi.Controller):
limit=limit,
marker=marker,
want_objects=True)
for instance in instance_list:
instance_obj.add_image_ref(context, instance)
except exception.MarkerNotFound:
msg = _('marker [%s] not found') % marker
raise exc.HTTPBadRequest(explanation=msg)
@@ -766,7 +769,8 @@ class Controller(wsgi.Controller):
context = req.environ['nova.context']
instance = self.compute_api.get(context, id,
want_objects=True)
req.cache_db_instance(instance)
req.cache_db_instance(instance_obj.add_image_ref(context,
instance))
return self._view_builder.show(req, instance)
except exception.NotFound:
msg = _("Instance could not be found")

View File

@@ -14,6 +14,7 @@
from nova.cells import opts as cells_opts
from nova.cells import rpcapi as cells_rpcapi
from nova import compute
from nova.compute import flavors
from nova import db
from nova import exception
@@ -567,6 +568,20 @@ class Instance(base.NovaPersistentObject, base.NovaObject):
self.obj_reset_changes(['metadata'])
def add_image_ref(context, instance):
"""Helper method to add image_ref to instance object."""
if not instance['image_ref']:
compute_api = compute.API()
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
context, instance['uuid'])
if compute_api.is_volume_backed_instance(context, instance, bdms):
props = bdms.root_metadata(
context, compute_api.image_api,
compute_api.volume_api)
instance['image_ref'] = props['image_id']
return instance
def _make_instance_list(context, inst_list, db_inst_list, expected_attrs):
get_fault = expected_attrs and 'fault' in expected_attrs
inst_faults = {}

View File

@@ -196,6 +196,8 @@ class ServersControllerTest(ControllerTest):
def setUp(self):
super(ServersControllerTest, self).setUp()
self.compute_api = self.controller.compute_api
self.context = context.RequestContext('fake', 'fake')
def test_can_check_loaded_extensions(self):
self.ext_mgr.extensions = {'os-fake': None}
@@ -259,6 +261,25 @@ class ServersControllerTest(ControllerTest):
res_dict = self.controller.show(req, FAKE_UUID)
self.assertEqual(res_dict['server']['id'], FAKE_UUID)
def test_get_server_no_image(self):
def return_instance(self, *args, **kwargs):
return fakes.stub_instance(id=1, uuid=FAKE_UUID,
project_id=str(uuid.uuid4()),
image_ref='')
def fake_add_image_ref(context, instance):
instance['image_ref'] = 'fake_image'
return instance
self.stubs.Set(db, 'instance_get_by_uuid', return_instance)
self.stubs.Set(instance_obj, 'add_image_ref', fake_add_image_ref)
req = fakes.HTTPRequest.blank('/fake/servers/%s' % FAKE_UUID)
server = self.controller.show(req, FAKE_UUID)
self.assertEqual('fake_image', server['server']['image']['id'])
def test_unique_host_id(self):
"""Create two servers with the same host and different
project_ids and check that the hostId's are unique.
@@ -517,6 +538,29 @@ class ServersControllerTest(ControllerTest):
self.assertEqual(s['links'], expected_links)
def test_get_servers_no_image(self):
def fake_get_all(compute_self, context, search_opts=None,
sort_key=None, sort_dir='desc',
limit=None, marker=None, want_objects=False):
db_list = [fakes.stub_instance(100,
uuid=FAKE_UUID,
image_ref='')]
return instance_obj._make_instance_list(
context, objects.InstanceList(), db_list, FIELDS)
def fake_add_image_ref(context, instance):
instance['image_ref'] = 'fake_image'
return instance
self.stubs.Set(instance_obj, 'add_image_ref', fake_add_image_ref)
self.stubs.Set(compute_api.API, 'get_all', fake_get_all)
req = fakes.HTTPRequest.blank('/fake/servers/detail')
res_dict = self.controller.detail(req)
for s in res_dict['servers']:
self.assertEqual('fake_image', s['image']['id'])
def test_get_servers_with_limit(self):
req = fakes.HTTPRequest.blank('/fake/servers?limit=3')
res_dict = self.controller.index(req)

View File

@@ -21,6 +21,7 @@ import netaddr
from nova.cells import rpcapi as cells_rpcapi
from nova.compute import flavors
from nova import context
from nova import db
from nova import exception
from nova.network import model as network_model
@@ -1088,3 +1089,14 @@ class TestInstanceObjectMisc(test.NoDBTestCase):
self.stubs.Set(instance, '_INSTANCE_OPTIONAL_JOINED_FIELDS', ['bar'])
self.assertEqual(['bar'], instance._expected_cols(['foo', 'bar']))
self.assertIsNone(instance._expected_cols(None))
class TestAddImageRef(test.TestCase):
@mock.patch('nova.objects.BlockDeviceMappingList.root_metadata')
def test_add_image_ref(self, mock_root_metadata):
mock_root_metadata.return_value = {'image_id': 'fake_image'}
fake_instance = fakes.stub_instance(id=1, uuid=fakes.FAKE_UUID,
image_ref='')
ctx = context.RequestContext('fake-user', 'fake-project')
new_instance = instance.add_image_ref(ctx, fake_instance)
self.assertEqual('fake_image', new_instance['image_ref'])