Display first volume image_metadata as an instance image
When instance is created from cinder volume, it's image is not displayed Nowdays using cinder as instance source becomes more widespread, so there is sense in displaying instance image, when instance is created from cinder volumes. We're trying to get volume_image_metadata from the first volume of the instance, when instance doesn't have image attribute itself. First volume is suggested based on its device name (eg. '/dev/vda'). This info is displayed only in instances list, not in detail overview. Change-Id: I00aa9ef07d1680bb2390a30271bb39cd7bea6329
This commit is contained in:
parent
4e8e907986
commit
3c82a38f71
@ -185,6 +185,7 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
api.network: (
|
||||
'servers_update_addresses',
|
||||
),
|
||||
api.cinder: ('volume_list',),
|
||||
})
|
||||
def _get_index(self, use_servers_update_address=True):
|
||||
servers = self.servers.list()
|
||||
@ -268,6 +269,7 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'tenant_absolute_limits',
|
||||
'flavor_list'),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.cinder: ('volume_list',),
|
||||
})
|
||||
def test_index_server_list_exception(self):
|
||||
search_opts = {'marker': None, 'paginate': True}
|
||||
@ -306,6 +308,7 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
api.neutron: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',),
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',),
|
||||
})
|
||||
def test_index_flavor_list_exception(self):
|
||||
servers = self.servers.list()
|
||||
@ -364,6 +367,7 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
api.neutron: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',),
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',),
|
||||
})
|
||||
def test_index_with_instance_booted_from_volume(self):
|
||||
volume_server = self.servers.first()
|
||||
@ -447,7 +451,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'flavor_list',
|
||||
'server_delete',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_delete_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -480,7 +485,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'flavor_list',
|
||||
'server_delete',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_delete_instance_error_state(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -515,7 +521,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'flavor_list',
|
||||
'server_delete',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_delete_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -551,7 +558,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_pause_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -590,7 +598,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_pause_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -629,7 +638,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_unpause_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -668,7 +678,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_unpause_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -706,7 +717,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'server_list_paged',
|
||||
'flavor_list',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_reboot_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -740,7 +752,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'server_list_paged',
|
||||
'flavor_list',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_reboot_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -774,7 +787,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'server_list_paged',
|
||||
'flavor_list',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_soft_reboot_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -810,7 +824,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_suspend_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -853,7 +868,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_suspend_instance_if_placed_on_2nd_page(self):
|
||||
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
|
||||
servers = self.servers.list()[:3]
|
||||
@ -897,7 +913,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_suspend_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -936,7 +953,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_resume_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -976,7 +994,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available'),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_resume_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -1016,7 +1035,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_shelve_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -1054,7 +1074,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_shelve_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -1093,7 +1114,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_unshelve_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -1133,7 +1155,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_unshelve_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -1173,7 +1196,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_lock_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -1214,7 +1238,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_lock_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -1257,7 +1282,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available'),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_unlock_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -1298,7 +1324,8 @@ class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
|
||||
'extension_supported',
|
||||
'is_feature_available'),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_unlock_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
@ -1812,6 +1839,7 @@ class InstanceTests(InstanceTestBase):
|
||||
api.neutron: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',),
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',),
|
||||
})
|
||||
def _test_instances_index_retrieve_password_action(self):
|
||||
servers = self.servers.list()
|
||||
@ -4107,6 +4135,7 @@ class InstanceLaunchInstanceTests(InstanceTestBase,
|
||||
api.neutron: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',),
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',),
|
||||
})
|
||||
def test_launch_button_attributes(self):
|
||||
servers = self.servers.list()
|
||||
@ -4171,6 +4200,7 @@ class InstanceLaunchInstanceTests(InstanceTestBase,
|
||||
api.neutron: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',),
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',),
|
||||
})
|
||||
def test_launch_button_disabled_when_quota_exceeded(self):
|
||||
servers = self.servers.list()
|
||||
@ -4360,6 +4390,7 @@ class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
|
||||
api.neutron: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',),
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',),
|
||||
})
|
||||
def test_index_options_after_migrate(self):
|
||||
servers = self.servers.list()
|
||||
@ -4936,6 +4967,7 @@ class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
|
||||
api.neutron: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',),
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',),
|
||||
})
|
||||
def test_index_form_action_with_pagination(self):
|
||||
# The form action on the next page should have marker
|
||||
@ -5022,7 +5054,8 @@ class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
|
||||
'flavor_list',
|
||||
'server_delete',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_delete_instance_with_pagination(self):
|
||||
# Instance should be deleted from the next page.
|
||||
|
||||
@ -5145,7 +5178,8 @@ class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
|
||||
'flavor_list',
|
||||
'server_unrescue',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.cinder: ('volume_list',)})
|
||||
def test_unrescue_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
|
@ -125,12 +125,23 @@ class IndexView(tables.PagedTableMixin, tables.DataTableView):
|
||||
|
||||
return instances
|
||||
|
||||
def _get_volumes(self):
|
||||
# Gather our volumes to get their image metadata for instance
|
||||
try:
|
||||
volumes = api.cinder.volume_list(self.request)
|
||||
return dict((str(volume.id), volume) for volume in volumes)
|
||||
except Exception:
|
||||
exceptions.handle(self.request, ignore=True)
|
||||
return {}
|
||||
|
||||
def get_data(self):
|
||||
marker, sort_dir = self._get_marker()
|
||||
search_opts = self.get_filters({'marker': marker, 'paginate': True})
|
||||
|
||||
image_dict, flavor_dict = futurist_utils.call_functions_parallel(
|
||||
self._get_images, self._get_flavors)
|
||||
image_dict, flavor_dict, volume_dict = \
|
||||
futurist_utils.call_functions_parallel(
|
||||
self._get_images, self._get_flavors, self._get_volumes
|
||||
)
|
||||
|
||||
non_api_filter_info = (
|
||||
('image_name', 'image', image_dict.values()),
|
||||
@ -155,6 +166,26 @@ class IndexView(tables.PagedTableMixin, tables.DataTableView):
|
||||
# until the call is deprecated in api itself
|
||||
else:
|
||||
instance.image['name'] = _("-")
|
||||
# Otherwise trying to get image from volume metadata
|
||||
else:
|
||||
instance_volumes = [
|
||||
attachment
|
||||
for volume in volume_dict.values()
|
||||
for attachment in volume.attachments
|
||||
if attachment['server_id'] == instance.id
|
||||
]
|
||||
# Sorting attached volumes by device name (eg '/dev/sda')
|
||||
instance_volumes.sort(key=lambda attach: attach['device'])
|
||||
# While instance from volume is being created,
|
||||
# it does not have volumes
|
||||
if instance_volumes:
|
||||
# Getting volume object, which is as attached
|
||||
# as the first device
|
||||
boot_volume = volume_dict[instance_volumes[0]['id']]
|
||||
if hasattr(boot_volume, "volume_image_metadata"):
|
||||
instance.image = image_dict[
|
||||
boot_volume.volume_image_metadata['image_id']
|
||||
]
|
||||
|
||||
flavor_id = instance.flavor["id"]
|
||||
if flavor_id in flavor_dict:
|
||||
|
Loading…
Reference in New Issue
Block a user