resource tracker style pci resource management

pci device resource should be managed via a method very like
vcpu/mem. allocte device in the Claim, release them when fail
or instance deleted.

Change-Id: Ia17a9f6bbaec358d244d4492798869b0e0a6a8cc
Closes-Bug: #1383465
This commit is contained in:
Yongli he 2014-10-28 10:04:10 +08:00 committed by Yongli He
parent c6a19f36e2
commit 58fbfdb9bf
6 changed files with 66 additions and 87 deletions

View File

@ -189,9 +189,9 @@ class Claim(NopClaim):
self.context, self.instance['uuid'])
if pci_requests.requests:
can_claim = self.tracker.pci_tracker.stats.support_requests(
pci_requests.requests)
if not can_claim:
devs = self.tracker.pci_tracker.claim_instance(self.context,
self.instance)
if not devs:
return _('Claim pci failed.')
def _test_ext_resources(self, limits):

View File

@ -748,11 +748,12 @@ class ResourceTracker(object):
self.stats.update_stats_for_instance(instance)
if self.pci_tracker:
self.pci_tracker.update_pci_for_instance(context, instance)
# if it's a new or deleted instance:
if is_new_instance or is_deleted_instance:
if self.pci_tracker:
self.pci_tracker.update_pci_for_instance(context,
instance,
sign=sign)
# new instance, update compute node resource usage:
self._update_usage(instance, sign=sign)

View File

@ -18,8 +18,6 @@ import collections
from oslo_log import log as logging
from nova.compute import task_states
from nova.compute import vm_states
from nova import exception
from nova.i18n import _LW
from nova import objects
@ -167,7 +165,8 @@ class PciDevTracker(object):
devs = self.stats.consume_requests(pci_requests.requests,
instance_cells)
if not devs:
raise exception.PciDeviceRequestFailed(pci_requests)
return None
for dev in devs:
device.claim(dev, instance)
if instance_numa_topology and any(
@ -181,6 +180,22 @@ class PciDevTracker(object):
for dev in devs:
device.allocate(dev, instance)
def allocate_instance(self, instance):
devs = self.claims.pop(instance['uuid'], [])
self._allocate_instance(instance, devs)
if devs:
self.allocations[instance['uuid']] += devs
def claim_instance(self, context, instance):
if not self.pci_devs:
return
devs = self._claim_instance(context, instance)
if devs:
self.claims[instance['uuid']] = devs
return devs
return None
def _free_device(self, dev, instance=None):
device.free(dev, instance)
stale = self.stale.pop(dev.address, None)
@ -199,36 +214,22 @@ class PciDevTracker(object):
dev.instance_uuid == instance['uuid']):
self._free_device(dev)
def update_pci_for_instance(self, context, instance):
"""Update instance's pci usage information.
def free_instance(self, context, instance):
if self.allocations.pop(instance['uuid'], None):
self._free_instance(instance)
elif self.claims.pop(instance['uuid'], None):
self._free_instance(instance)
The caller should hold the COMPUTE_RESOURCE_SEMAPHORE lock
def update_pci_for_instance(self, context, instance, sign):
"""Update PCI usage information if devices are de/allocated.
"""
if not self.pci_devs:
return
uuid = instance['uuid']
vm_state = instance['vm_state']
task_state = instance['task_state']
if vm_state == vm_states.DELETED:
if self.allocations.pop(uuid, None):
self._free_instance(instance)
elif self.claims.pop(uuid, None):
self._free_instance(instance)
elif task_state == task_states.RESIZE_MIGRATED:
devs = self.allocations.pop(uuid, None)
if devs:
self._free_instance(instance)
elif task_state == task_states.RESIZE_FINISH:
devs = self.claims.pop(uuid, None)
if devs:
self._allocate_instance(instance, devs)
self.allocations[uuid] = devs
elif (uuid not in self.allocations and
uuid not in self.claims):
devs = self._claim_instance(context, instance)
if devs:
self._allocate_instance(instance, devs)
self.allocations[uuid] = devs
if sign == -1:
self.free_instance(context, instance)
if sign == 1:
self.allocate_instance(instance)
def update_pci_for_migration(self, context, instance, sign=1):
"""Update instance's pci usage information when it is migrated.

View File

@ -159,8 +159,7 @@ class PciDeviceStats(object):
" on the compute node semaphore"))
for d in range(len(alloc_devices)):
self.add_device(alloc_devices.pop())
raise exception.PciDeviceRequestFailed(requests=pci_requests)
return None
for pool in pools:
if pool['count'] >= count:
num_alloc = count

View File

@ -18,11 +18,9 @@ import copy
import mock
import nova
from nova.compute import task_states
from nova.compute import vm_states
from nova import context
from nova import db
from nova import exception
from nova import objects
from nova.pci import device
from nova.pci import manager
@ -182,8 +180,12 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_update_pci_for_instance_active(self, mock_get):
self._create_pci_requests_object(mock_get, fake_pci_requests)
self.tracker.update_pci_for_instance(None, self.inst)
self.tracker.claim_instance(None, self.inst)
self.assertEqual(len(self.tracker.claims[self.inst['uuid']]), 2)
self.tracker.update_pci_for_instance(None, self.inst, sign=1)
self.assertEqual(len(self.tracker.allocations[self.inst['uuid']]), 2)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 1)
self.assertEqual(free_devs[0].vendor_id, 'v')
@ -193,13 +195,16 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
pci_requests = copy.deepcopy(fake_pci_requests)
pci_requests[0]['count'] = 4
self._create_pci_requests_object(mock_get, pci_requests)
self.assertRaises(exception.PciDeviceRequestFailed,
self.tracker.update_pci_for_instance,
None,
self.inst)
self.tracker.claim_instance(None, self.inst)
self.assertEqual(len(self.tracker.claims[self.inst['uuid']]), 0)
devs = self.tracker.update_pci_for_instance(None,
self.inst,
sign=1)
self.assertEqual(len(self.tracker.allocations[self.inst['uuid']]), 0)
self.assertIsNone(devs)
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_update_pci_for_instance_with_numa(self, mock_get):
def test_pci_claim_instance_with_numa(self, mock_get):
fake_db_dev_3 = dict(fake_db_dev_1, id=4, address='0000:00:00.4')
fake_devs_numa = copy.deepcopy(fake_db_devs)
fake_devs_numa.append(fake_db_dev_3)
@ -211,61 +216,34 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self.inst.numa_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=1, cpuset=set([1, 2]), memory=512)])
self.tracker.update_pci_for_instance(None, self.inst)
self.tracker.claim_instance(None, self.inst)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(2, len(free_devs))
self.assertEqual('v1', free_devs[0].vendor_id)
self.assertEqual('v1', free_devs[1].vendor_id)
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_update_pci_for_instance_with_numa_fail(self, mock_get):
def test_pci_claim_instance_with_numa_fail(self, mock_get):
self._create_pci_requests_object(mock_get, fake_pci_requests)
self.inst.numa_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=1, cpuset=set([1, 2]), memory=512)])
self.assertRaises(exception.PciDeviceRequestFailed,
self.tracker.update_pci_for_instance,
None,
self.inst)
self.assertIsNone(self.tracker.claim_instance(None, self.inst))
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_update_pci_for_instance_deleted(self, mock_get):
self._create_pci_requests_object(mock_get, fake_pci_requests)
self.tracker.update_pci_for_instance(None, self.inst)
self.tracker.claim_instance(None, self.inst)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 1)
self.inst.vm_state = vm_states.DELETED
self.tracker.update_pci_for_instance(None, self.inst)
self.tracker.update_pci_for_instance(None, self.inst, -1)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 3)
self.assertEqual(set([dev.vendor_id for
dev in self.tracker.pci_devs]),
set(['v', 'v1']))
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_update_pci_for_instance_resize_source(self, mock_get):
self._create_pci_requests_object(mock_get, fake_pci_requests)
self.tracker.update_pci_for_instance(None, self.inst)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 1)
self.inst.task_state = task_states.RESIZE_MIGRATED
self.tracker.update_pci_for_instance(None, self.inst)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 3)
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_update_pci_for_instance_resize_dest(self, mock_get):
self._create_pci_requests_object(mock_get, fake_pci_requests)
self.tracker.update_pci_for_migration(None, self.inst)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 1)
self.assertEqual(len(self.tracker.claims['fake-inst-uuid']), 2)
self.assertNotIn('fake-inst-uuid', self.tracker.allocations)
self.inst.task_state = task_states.RESIZE_FINISH
self.tracker.update_pci_for_instance(None, self.inst)
self.assertEqual(len(self.tracker.allocations['fake-inst-uuid']), 2)
self.assertNotIn('fake-inst-uuid', self.tracker.claims)
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_update_pci_for_migration_in(self, mock_get):
self._create_pci_requests_object(mock_get, fake_pci_requests)
@ -316,10 +294,12 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self._create_pci_requests_object(mock_get,
[{'count': 1, 'spec': [{'vendor_id': 'v'}]}])
self.tracker.update_pci_for_instance(None, self.inst)
self.tracker.claim_instance(None, self.inst)
self.tracker.update_pci_for_instance(None, self.inst, sign=1)
self._create_pci_requests_object(mock_get,
[{'count': 1, 'spec': [{'vendor_id': 'v1'}]}])
self.tracker.update_pci_for_instance(None, inst_2)
self.tracker.claim_instance(None, inst_2)
self.tracker.update_pci_for_instance(None, inst_2, sign=1)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 1)
self.assertEqual(free_devs[0].vendor_id, 'v')
@ -340,7 +320,8 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self._create_pci_requests_object(mock_get,
[{'count': 1, 'spec': [{'vendor_id': 'v'}]}])
self.tracker.update_pci_for_instance(None, self.inst)
self.tracker.claim_instance(None, self.inst)
self.tracker.update_pci_for_instance(None, self.inst, sign=1)
self._create_pci_requests_object(mock_get,
[{'count': 1, 'spec': [{'vendor_id': 'v1'}]}])
self.tracker.update_pci_for_migration(None, inst_2)

View File

@ -159,9 +159,8 @@ class PciDeviceStatsTestCase(test.NoDBTestCase):
self.assertEqual(0, len(devs))
def test_consume_requests_failed(self):
self.assertRaises(exception.PciDeviceRequestFailed,
self.pci_stats.consume_requests,
pci_requests_multiple)
self.assertIsNone(self.pci_stats.consume_requests(
pci_requests_multiple))
def test_support_requests_numa(self):
cells = [objects.NUMACell(id=0, cpuset=set(), memory=0),
@ -191,9 +190,7 @@ class PciDeviceStatsTestCase(test.NoDBTestCase):
def test_consume_requests_numa_failed(self):
cells = [objects.NUMACell(id=0, cpuset=set(), memory=0)]
self.assertRaises(exception.PciDeviceRequestFailed,
self.pci_stats.consume_requests,
pci_requests, cells)
self.assertIsNone(self.pci_stats.consume_requests(pci_requests, cells))
def test_consume_requests_no_numa_info(self):
cells = [objects.NUMACell(id=0, cpuset=set(), memory=0)]