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:
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user