Pass bdm info to _get_instance_disk_info method

If bdm info is not passed to the '_get_instance_disk_info' method,
then in case of processing qcow2 backing file, it raises permission
denied error provided the backing is belonging to an attached and
NFS-hosted Cinder volume.

Passed bdm info to the '_get_instance_disk_info' method if any
volumes are attached to the instance.

Co-Authored-By: Ankit Agrawal <ankit11.agrawal@nttdata.com>
Closes-Bug: #1416132
Change-Id: I5d5c64ea4d304022282ec9ab121e295f3c9e0d03
This commit is contained in:
Abhijeet Malawade 2015-09-04 00:21:47 -07:00 committed by Ankit Agrawal
parent b57fbc725f
commit 1345d0fe1c
2 changed files with 93 additions and 12 deletions

View File

@ -10552,11 +10552,15 @@ class LibvirtConnTestCase(test.NoDBTestCase):
drvr._undefine_domain(instance)
@mock.patch.object(host.Host, "list_instance_domains")
def test_disk_over_committed_size_total(self, mock_list):
@mock.patch.object(objects.BlockDeviceMappingList, "bdms_by_instance_uuid")
@mock.patch.object(objects.InstanceList, "get_by_filters")
def test_disk_over_committed_size_total(self, mock_get, mock_bdms,
mock_list):
# Ensure destroy calls managedSaveRemove for saved instance.
class DiagFakeDomain(object):
def __init__(self, name):
self._name = name
self._uuid = str(uuid.uuid4())
def ID(self):
return 1
@ -10565,14 +10569,15 @@ class LibvirtConnTestCase(test.NoDBTestCase):
return self._name
def UUIDString(self):
return "19479fee-07a5-49bb-9138-d3738280d63c"
return self._uuid
def XMLDesc(self, flags):
return "<domain/>"
mock_list.return_value = [
instance_domains = [
DiagFakeDomain("instance0000001"),
DiagFakeDomain("instance0000002")]
mock_list.return_value = instance_domains
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@ -10592,21 +10597,39 @@ class LibvirtConnTestCase(test.NoDBTestCase):
def get_info(instance_name, xml, **kwargs):
return fake_disks.get(instance_name)
instance_uuids = [dom.UUIDString() for dom in instance_domains]
instances = [objects.Instance(
uuid=instance_uuids[0],
root_device_name='/dev/vda'),
objects.Instance(
uuid=instance_uuids[1],
root_device_name='/dev/vdb')
]
mock_get.return_value = instances
with mock.patch.object(drvr,
"_get_instance_disk_info") as mock_info:
mock_info.side_effect = get_info
result = drvr._get_disk_over_committed_size_total()
self.assertEqual(result, 10653532160)
mock_list.assert_called_with(only_guests=True, only_running=True)
self.assertTrue(mock_info.called)
mock_list.assert_called_once_with()
self.assertEqual(2, mock_info.call_count)
filters = {'uuid': instance_uuids}
mock_get.assert_called_once_with(mock.ANY, filters, use_slave=True)
mock_bdms.assert_called_with(mock.ANY, instance_uuids)
@mock.patch.object(host.Host, "list_instance_domains")
def test_disk_over_committed_size_total_eperm(self, mock_list):
@mock.patch.object(objects.BlockDeviceMappingList, "bdms_by_instance_uuid")
@mock.patch.object(objects.InstanceList, "get_by_filters")
def test_disk_over_committed_size_total_eperm(self, mock_get, mock_bdms,
mock_list):
# Ensure destroy calls managedSaveRemove for saved instance.
class DiagFakeDomain(object):
def __init__(self, name):
self._name = name
self._uuid = str(uuid.uuid4())
def ID(self):
return 1
@ -10615,14 +10638,15 @@ class LibvirtConnTestCase(test.NoDBTestCase):
return self._name
def UUIDString(self):
return "19479fee-07a5-49bb-9138-d3738280d63c"
return self._uuid
def XMLDesc(self, flags):
return "<domain/>"
mock_list.return_value = [
instance_domains = [
DiagFakeDomain("instance0000001"),
DiagFakeDomain("instance0000002")]
mock_list.return_value = instance_domains
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@ -10639,24 +10663,46 @@ class LibvirtConnTestCase(test.NoDBTestCase):
'disk_size': '10737418240',
'over_committed_disk_size': '21474836480'}]}
def side_effect(name, dom):
def side_effect(name, dom, block_device_info):
if name == 'instance0000001':
self.assertEqual('/dev/vda',
block_device_info['root_device_name'])
raise OSError(errno.EACCES, 'Permission denied')
if name == 'instance0000002':
self.assertEqual('/dev/vdb',
block_device_info['root_device_name'])
return fake_disks.get(name)
get_disk_info = mock.Mock()
get_disk_info.side_effect = side_effect
drvr._get_instance_disk_info = get_disk_info
instance_uuids = [dom.UUIDString() for dom in instance_domains]
instances = [objects.Instance(
uuid=instance_uuids[0],
root_device_name='/dev/vda'),
objects.Instance(
uuid=instance_uuids[1],
root_device_name='/dev/vdb')
]
mock_get.return_value = instances
result = drvr._get_disk_over_committed_size_total()
self.assertEqual(21474836480, result)
mock_list.assert_called_with(only_guests=True, only_running=True)
mock_list.assert_called_once_with()
self.assertEqual(2, get_disk_info.call_count)
filters = {'uuid': instance_uuids}
mock_get.assert_called_once_with(mock.ANY, filters, use_slave=True)
mock_bdms.assert_called_with(mock.ANY, instance_uuids)
@mock.patch.object(host.Host, "list_instance_domains",
return_value=[mock.MagicMock(name='foo')])
@mock.patch.object(libvirt_driver.LibvirtDriver, "_get_instance_disk_info",
side_effect=exception.VolumeBDMPathNotFound(path='bar'))
@mock.patch.object(objects.BlockDeviceMappingList, "bdms_by_instance_uuid")
@mock.patch.object(objects.InstanceList, "get_by_filters")
def test_disk_over_committed_size_total_bdm_not_found(self,
mock_get,
mock_bdms,
mock_get_disk_info,
mock_list_domains):
# Tests that we handle VolumeBDMPathNotFound gracefully.

View File

@ -6923,11 +6923,46 @@ class LibvirtDriver(driver.ComputeDriver):
"""Return total over committed disk size for all instances."""
# Disk size that all instance uses : virtual_size - disk_size
disk_over_committed_size = 0
for guest in self._host.list_guests():
instance_domains = self._host.list_instance_domains()
if not instance_domains:
return disk_over_committed_size
# Get all instance uuids
instance_uuids = [dom.UUIDString() for dom in instance_domains]
ctx = nova_context.get_admin_context()
# Get instance object list by uuid filter
filters = {'uuid': instance_uuids}
# NOTE(ankit): objects.InstanceList.get_by_filters method is
# getting called twice one is here and another in the
# _update_available_resource method of resource_tracker. Since
# _update_available_resource method is synchronized, there is a
# possibility the instances list retrieved here to calculate
# disk_over_committed_size would differ to the list you would get
# in _update_available_resource method for calculating usages based
# on instance utilization.
local_instance_list = objects.InstanceList.get_by_filters(
ctx, filters, use_slave=True)
# Convert instance list to dictionary with instace uuid as key.
local_instances = {inst.uuid: inst for inst in local_instance_list}
# Get bdms by instance uuids
bdms = objects.BlockDeviceMappingList.bdms_by_instance_uuid(
ctx, instance_uuids)
for dom in instance_domains:
try:
guest = libvirt_guest.Guest(dom)
xml = guest.get_xml_desc()
disk_infos = self._get_instance_disk_info(guest.name, xml)
block_device_info = None
if guest.uuid in local_instances:
# Get block device info for instance
block_device_info = driver.get_block_device_info(
local_instances[guest.uuid], bdms[guest.uuid])
disk_infos = self._get_instance_disk_info(guest.name, xml,
block_device_info=block_device_info)
for info in disk_infos:
disk_over_committed_size += int(
info['over_committed_disk_size'])