Merge "pci: Move PCI devices and PCI requests into migration context"

This commit is contained in:
Jenkins 2016-06-03 17:24:16 +00:00 committed by Gerrit Code Review
commit a224d5e8c0
13 changed files with 240 additions and 211 deletions

View File

@ -22,7 +22,6 @@ from oslo_log import log as logging
from nova import exception
from nova.i18n import _
from nova.i18n import _LI
from nova.i18n import _LW
from nova import objects
from nova.virt import hardware
@ -201,9 +200,7 @@ class Claim(NopClaim):
if host_topology:
host_topology = objects.NUMATopology.obj_from_db_obj(
host_topology)
pci_requests = objects.InstancePCIRequests.get_by_instance_uuid(
self.context, self.instance.uuid)
pci_requests = self._pci_requests
pci_stats = None
if pci_requests.requests:
pci_stats = self.tracker.pci_tracker.stats
@ -300,18 +297,3 @@ class MoveClaim(Claim):
self.tracker.drop_move_claim(
self.context,
self.instance, instance_type=self.instance_type)
def create_migration_context(self):
if not self.migration:
LOG.warning(
_LW("Can't create a migration_context record without a "
"migration object specified."),
instance=self.instance)
return
mig_context = objects.MigrationContext(
context=self.context, instance_uuid=self.instance.uuid,
migration_id=self.migration.id,
old_numa_topology=self.instance.numa_topology,
new_numa_topology=self.claimed_numa_topology)
return mig_context

View File

@ -35,6 +35,7 @@ from nova import objects
from nova.objects import base as obj_base
from nova.objects import migration as migration_obj
from nova.pci import manager as pci_manager
from nova.pci import request as pci_request
from nova import rpc
from nova.scheduler import client as scheduler_client
from nova import utils
@ -217,15 +218,49 @@ class ResourceTracker(object):
"GB", {'flavor': instance.root_gb,
'overhead': overhead.get('disk_gb', 0)})
pci_requests = objects.InstancePCIRequests.\
get_by_instance_uuid_and_newness(
context, instance.uuid, True)
# TODO(moshele): we are recreating the pci requests even if
# there was no change on resize. This will cause allocating
# the old/new pci device in the resize phase. In the future
# we would like to optimise this.
new_pci_requests = pci_request.get_pci_requests_from_flavor(
new_instance_type)
new_pci_requests.instance_uuid = instance.uuid
# PCI requests come from two sources: instance flavor and
# SR-IOV ports. SR-IOV ports pci_request don't have an alias_name.
# On resize merge the SR-IOV ports pci_requests with the new
# instance flavor pci_requests.
if instance.pci_requests:
for request in instance.pci_requests.requests:
if request.alias_name is None:
new_pci_requests.requests.append(request)
claim = claims.MoveClaim(context, instance, new_instance_type,
image_meta, self, self.compute_node,
pci_requests, overhead=overhead,
new_pci_requests, overhead=overhead,
limits=limits)
claim.migration = migration
instance.migration_context = claim.create_migration_context()
claimed_pci_devices_objs = []
if self.pci_tracker:
# NOTE(jaypipes): ComputeNode.pci_device_pools is set below
# in _update_usage_from_instance().
claimed_pci_devices_objs = self.pci_tracker.claim_instance(
context, new_pci_requests, claim.claimed_numa_topology)
claimed_pci_devices = objects.PciDeviceList(
objects=claimed_pci_devices_objs)
# TODO(jaypipes): Move claimed_numa_topology out of the Claim's
# constructor flow so the Claim constructor only tests whether
# resources can be claimed, not consume the resources directly.
mig_context = objects.MigrationContext(
context=context, instance_uuid=instance.uuid,
migration_id=migration.id,
old_numa_topology=instance.numa_topology,
new_numa_topology=claim.claimed_numa_topology,
old_pci_devices=instance.pci_devices,
new_pci_devices=claimed_pci_devices,
old_pci_requests=instance.pci_requests,
new_pci_requests=new_pci_requests)
instance.migration_context = mig_context
instance.save()
# Mark the resources in-use for the resize landing on this
@ -323,9 +358,12 @@ class ResourceTracker(object):
usage = self._get_usage_dict(
itype, numa_topology=numa_topology)
if self.pci_tracker:
self.pci_tracker.update_pci_for_migration(context,
instance,
sign=-1)
# free old allocated pci devices
old_pci_devices = self._get_migration_context_resource(
'pci_devices', instance, prefix='old_')
if old_pci_devices:
for pci_device in old_pci_devices:
self.pci_tracker.free_device(pci_device, instance)
self._update_usage(usage, sign=-1)
ctxt = context.elevated()
@ -685,8 +723,9 @@ class ResourceTracker(object):
def _get_migration_context_resource(self, resource, instance,
prefix='new_', itype=None):
migration_context = instance.migration_context
if migration_context:
return getattr(migration_context, prefix + resource)
resource = prefix + resource
if migration_context and resource in migration_context:
return getattr(migration_context, resource)
else:
return None
@ -710,7 +749,7 @@ class ResourceTracker(object):
record = self.tracked_instances.get(uuid, None)
itype = None
numa_topology = None
sign = 0
if same_node:
# same node resize. record usage for whichever instance type the
# instance is *not* in:
@ -720,6 +759,7 @@ class ResourceTracker(object):
migration)
numa_topology = self._get_migration_context_resource(
'numa_topology', instance)
sign = 1
else:
# instance record already has new flavor, hold space for a
# possible revert to the old instance type:
@ -752,8 +792,9 @@ class ResourceTracker(object):
if itype:
usage = self._get_usage_dict(
itype, numa_topology=numa_topology)
if self.pci_tracker:
self.pci_tracker.update_pci_for_migration(context, instance)
if self.pci_tracker and sign:
self.pci_tracker.update_pci_for_instance(
context, instance, sign=sign)
self._update_usage(usage)
if self.pci_tracker:
obj = self.pci_tracker.stats.to_device_pools_obj()

View File

@ -46,6 +46,7 @@ Possible Values:
Services which consume this:
* nova-api
* nova-compute
Related options:

View File

@ -52,6 +52,9 @@ _INSTANCE_OPTIONAL_NON_COLUMN_FIELDS = ['fault', 'flavor', 'old_flavor',
_INSTANCE_EXTRA_FIELDS = ['numa_topology', 'pci_requests',
'flavor', 'vcpu_model', 'migration_context',
'keypairs']
# These are fields that applied/drooped by migration_context
_MIGRATION_CONTEXT_ATTRS = ['numa_topology', 'pci_requests',
'pci_devices']
# These are fields that can be specified as expected_attrs
INSTANCE_OPTIONAL_ATTRS = (_INSTANCE_OPTIONAL_JOINED_FIELDS +
@ -878,18 +881,27 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
def apply_migration_context(self):
if self.migration_context:
self.numa_topology = self.migration_context.new_numa_topology
self._set_migration_context_to_instance(prefix='new_')
else:
LOG.debug("Trying to apply a migration context that does not "
"seem to be set for this instance", instance=self)
def revert_migration_context(self):
if self.migration_context:
self.numa_topology = self.migration_context.old_numa_topology
self._set_migration_context_to_instance(prefix='old_')
else:
LOG.debug("Trying to revert a migration context that does not "
"seem to be set for this instance", instance=self)
def _set_migration_context_to_instance(self, prefix):
for inst_attr_name in _MIGRATION_CONTEXT_ATTRS:
setattr(self, inst_attr_name, None)
attr_name = prefix + inst_attr_name
if attr_name in self.migration_context:
attr_value = getattr(
self.migration_context, attr_name)
setattr(self, inst_attr_name, attr_value)
@contextlib.contextmanager
def mutated_migration_context(self):
"""Context manager to temporarily apply the migration context.
@ -898,12 +910,15 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
context will be saved which can cause incorrect resource tracking, and
should be avoided.
"""
current_numa_topo = self.numa_topology
current_values = {}
for attr_name in _MIGRATION_CONTEXT_ATTRS:
current_values[attr_name] = getattr(self, attr_name)
self.apply_migration_context()
try:
yield
finally:
self.numa_topology = current_numa_topo
for attr_name in _MIGRATION_CONTEXT_ATTRS:
setattr(self, attr_name, current_values[attr_name])
@base.remotable
def drop_migration_context(self):

View File

@ -13,6 +13,7 @@
# under the License.
from oslo_serialization import jsonutils
from oslo_utils import versionutils
from nova import db
from nova import exception
@ -33,7 +34,8 @@ class MigrationContext(base.NovaPersistentObject, base.NovaObject):
"""
# Version 1.0: Initial version
VERSION = '1.0'
# Version 1.1: Add old/new pci_devices and pci_requests
VERSION = '1.1'
fields = {
'instance_uuid': fields.UUIDField(),
@ -42,8 +44,25 @@ class MigrationContext(base.NovaPersistentObject, base.NovaObject):
nullable=True),
'old_numa_topology': fields.ObjectField('InstanceNUMATopology',
nullable=True),
'new_pci_devices': fields.ObjectField('PciDeviceList',
nullable=True),
'old_pci_devices': fields.ObjectField('PciDeviceList',
nullable=True),
'new_pci_requests': fields.ObjectField('InstancePCIRequests',
nullable=True),
'old_pci_requests': fields.ObjectField('InstancePCIRequests',
nullable=True),
}
@classmethod
def obj_make_compatible(cls, primitive, target_version):
target_version = versionutils.convert_version_to_tuple(target_version)
if target_version < (1, 1):
primitive.pop('old_pci_devices', None)
primitive.pop('new_pci_devices', None)
primitive.pop('old_pci_requests', None)
primitive.pop('new_pci_requests', None)
@classmethod
def obj_from_db_obj(cls, db_obj):
primitive = jsonutils.loads(db_obj)

View File

@ -26,7 +26,6 @@ from nova import objects
from nova.objects import fields
from nova.pci import stats
from nova.pci import whitelist
from nova.virt import hardware
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
@ -249,16 +248,27 @@ class PciDevTracker(object):
self.allocations[instance['uuid']] += devs
def claim_instance(self, context, pci_requests, instance_numa_topology):
if not self.pci_devs or not pci_requests.requests:
return
devs = []
if self.pci_devs and pci_requests.requests:
instance_uuid = pci_requests.instance_uuid
devs = self._claim_instance(context, pci_requests,
instance_numa_topology)
if devs:
self.claims[instance_uuid] = devs
return devs
instance_uuid = pci_requests.instance_uuid
devs = self._claim_instance(context, pci_requests,
instance_numa_topology)
if devs:
self.claims[instance_uuid] = devs
return devs
return None
def free_device(self, dev, instance):
"""Free device from pci resource tracker
:param dev: cloned pci device object that needs to be free
:param instance: the instance that this pci device
is allocated to
"""
for pci_dev in self.pci_devs:
# find the matching pci device in the pci resource tracker
# pci device. Once found one free it.
if dev == pci_dev and dev.instance_uuid == instance['uuid']:
self._free_device(pci_dev)
def _free_device(self, dev, instance=None):
freed_devs = dev.free(instance)
@ -297,27 +307,6 @@ class PciDevTracker(object):
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.
The caller should hold the COMPUTE_RESOURCE_SEMAPHORE lock.
:param sign: claim devices for instance when sign is 1, remove
the claims when sign is -1
"""
uuid = instance['uuid']
pci_requests = objects.InstancePCIRequests.get_by_instance(
context, instance)
instance_numa_topology = hardware.instance_topology_from_instance(
instance)
if sign == 1 and uuid not in self.claims:
devs = self._claim_instance(context, pci_requests,
instance_numa_topology)
if devs:
self.claims[uuid] = devs
if sign == -1 and uuid in self.claims:
self._free_instance(instance)
def clean_usage(self, instances, migrations, orphans):
"""Remove all usages for instances not passed in the parameter.

View File

@ -62,6 +62,7 @@ class ClaimTestCase(test.NoDBTestCase):
def setUp(self):
super(ClaimTestCase, self).setUp()
self.context = context.RequestContext('fake-user', 'fake-project')
self.instance = None
self.resources = self._fake_resources()
self.tracker = DummyTracker()
self.empty_requests = objects.InstancePCIRequests(
@ -224,34 +225,29 @@ class ClaimTestCase(test.NoDBTestCase):
@mock.patch('nova.pci.stats.PciDeviceStats.support_requests',
return_value=True)
def test_pci_pass(self, mock_supports):
def test_pci_pass(self, mock_pci_supports_requests):
request = objects.InstancePCIRequest(count=1,
spec=[{'vendor_id': 'v', 'product_id': 'p'}])
requests = objects.InstancePCIRequests(requests=[request])
# Claim.__init__() would raise ComputeResourcesUnavailable
# if Claim._test_pci() did not return None.
self._claim(requests=requests)
mock_supports.assert_called_once_with(requests.requests)
mock_pci_supports_requests.assert_called_once_with([request])
@mock.patch('nova.pci.stats.PciDeviceStats.support_requests',
return_value=False)
def test_pci_fail(self, mock_supports):
def test_pci_fail(self, mock_pci_supports_requests):
request = objects.InstancePCIRequest(count=1,
spec=[{'vendor_id': 'v', 'product_id': 'p'}])
requests = objects.InstancePCIRequests(requests=[request])
self.assertRaisesRegex(
exception.ComputeResourcesUnavailable,
'Claim pci failed.',
self._claim, requests=requests)
mock_pci_supports_requests.assert_called_once_with([request])
self.assertRaises(exception.ComputeResourcesUnavailable,
self._claim, requests=requests)
mock_supports.assert_called_once_with(requests.requests)
@mock.patch('nova.pci.stats.PciDeviceStats.support_requests',
return_value=True)
def test_pci_pass_no_requests(self, mock_supports):
# Claim.__init__() would raise ComputeResourcesUnavailable
# if Claim._test_pci() did not return None.
@mock.patch('nova.pci.stats.PciDeviceStats.support_requests')
def test_pci_pass_no_requests(self, mock_pci_supports_requests):
self._claim()
self.assertFalse(mock_supports.called)
self.assertFalse(mock_pci_supports_requests.called)
def test_numa_topology_no_limit(self):
huge_instance = objects.InstanceNUMATopology(
@ -422,30 +418,6 @@ class MoveClaimTestCase(ClaimTestCase):
claim = self._abort()
self.assertTrue(claim.tracker.rcalled)
def test_create_migration_context(self):
numa_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=1, cpuset=set([1, 2]), memory=512)])
claim = self._claim(numa_topology=numa_topology)
migration = objects.Migration(context=self.context, id=42)
claim.migration = migration
fake_mig_context = mock.Mock(spec=objects.MigrationContext)
@mock.patch('nova.db.instance_extra_get_by_instance_uuid',
return_value=None)
@mock.patch('nova.objects.MigrationContext',
return_value=fake_mig_context)
def _test(ctxt_mock, mock_get_extra):
claim.create_migration_context()
ctxt_mock.assert_called_once_with(
context=self.context, instance_uuid=self.instance.uuid,
migration_id=42, old_numa_topology=None,
new_numa_topology=mock.ANY)
self.assertIsInstance(ctxt_mock.call_args[1]['new_numa_topology'],
objects.InstanceNUMATopology)
self.assertEqual(migration, claim.migration)
_test()
def test_image_meta(self):
claim = self._claim()
self.assertIsInstance(claim.image_meta, objects.ImageMeta)

View File

@ -2928,6 +2928,8 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
instance = fake_instance.fake_instance_obj(self.context)
instance.migration_context = None
instance.numa_topology = None
instance.pci_requests = None
instance.pci_devices = None
instance.task_state = task_states.REBUILDING
instance.save(expected_task_state=[task_states.REBUILDING])
self.compute._rebuild_default_impl(self.context,

View File

@ -26,8 +26,10 @@ from nova.compute import vm_states
from nova import exception as exc
from nova import objects
from nova.objects import base as obj_base
from nova.objects import pci_device
from nova.pci import manager as pci_manager
from nova import test
from nova.tests.unit.objects import test_pci_device as fake_pci_device
_HOSTNAME = 'fake-host'
_NODENAME = 'fake-node'
@ -168,6 +170,8 @@ _INSTANCE_FIXTURES = [
root_gb=_INSTANCE_TYPE_FIXTURES[1]['root_gb'],
ephemeral_gb=_INSTANCE_TYPE_FIXTURES[1]['ephemeral_gb'],
numa_topology=_INSTANCE_NUMA_TOPOLOGIES['2mb'],
pci_requests=None,
pci_devices=None,
instance_type_id=1,
vm_state=vm_states.ACTIVE,
power_state=power_state.RUNNING,
@ -188,6 +192,8 @@ _INSTANCE_FIXTURES = [
root_gb=_INSTANCE_TYPE_FIXTURES[2]['root_gb'],
ephemeral_gb=_INSTANCE_TYPE_FIXTURES[2]['ephemeral_gb'],
numa_topology=None,
pci_requests=None,
pci_devices=None,
instance_type_id=2,
vm_state=vm_states.DELETED,
power_state=power_state.SHUTDOWN,
@ -267,6 +273,8 @@ _MIGRATION_INSTANCE_FIXTURES = {
root_gb=_INSTANCE_TYPE_FIXTURES[1]['root_gb'],
ephemeral_gb=_INSTANCE_TYPE_FIXTURES[1]['ephemeral_gb'],
numa_topology=_INSTANCE_NUMA_TOPOLOGIES['2mb'],
pci_requests=None,
pci_devices=None,
instance_type_id=1,
vm_state=vm_states.ACTIVE,
power_state=power_state.RUNNING,
@ -289,6 +297,8 @@ _MIGRATION_INSTANCE_FIXTURES = {
root_gb=_INSTANCE_TYPE_FIXTURES[2]['root_gb'],
ephemeral_gb=_INSTANCE_TYPE_FIXTURES[2]['ephemeral_gb'],
numa_topology=None,
pci_requests=None,
pci_devices=None,
instance_type_id=2,
vm_state=vm_states.ACTIVE,
power_state=power_state.RUNNING,
@ -311,6 +321,8 @@ _MIGRATION_INSTANCE_FIXTURES = {
root_gb=_INSTANCE_TYPE_FIXTURES[2]['root_gb'],
ephemeral_gb=_INSTANCE_TYPE_FIXTURES[2]['ephemeral_gb'],
numa_topology=None,
pci_requests=None,
pci_devices=None,
instance_type_id=2,
vm_state=vm_states.ACTIVE,
power_state=power_state.RUNNING,
@ -333,6 +345,8 @@ _MIGRATION_INSTANCE_FIXTURES = {
root_gb=_INSTANCE_TYPE_FIXTURES[2]['root_gb'],
ephemeral_gb=_INSTANCE_TYPE_FIXTURES[2]['ephemeral_gb'],
numa_topology=None,
pci_requests=None,
pci_devices=None,
instance_type_id=2,
vm_state=vm_states.ACTIVE,
power_state=power_state.RUNNING,
@ -1384,11 +1398,9 @@ class TestInstanceClaim(BaseTestCase):
@mock.patch('nova.pci.stats.PciDeviceStats.support_requests',
return_value=True)
@mock.patch('nova.pci.manager.PciDevTracker.claim_instance')
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid')
@mock.patch('nova.objects.MigrationList.get_in_progress_by_host_and_node')
def test_claim_with_pci(self, migr_mock, pci_mock,
pci_manager_mock, pci_stats_mock):
def test_claim_with_pci(self, migr_mock, pci_mock, pci_stats_mock):
# Test that a claim involving PCI requests correctly claims
# PCI devices on the host and sends an updated pci_device_pools
# attribute of the ComputeNode object.
@ -1398,12 +1410,17 @@ class TestInstanceClaim(BaseTestCase):
# upon the resource tracker being initialized...
self.rt.pci_tracker = pci_manager.PciDevTracker(mock.sentinel.ctx)
pci_pools = objects.PciDevicePoolList()
pci_manager_mock.return_value = pci_pools
pci_dev = pci_device.PciDevice.create(
None, fake_pci_device.dev_dict)
pci_devs = [pci_dev]
self.rt.pci_tracker.pci_devs = objects.PciDeviceList(objects=pci_devs)
request = objects.InstancePCIRequest(count=1,
spec=[{'vendor_id': 'v', 'product_id': 'p'}])
pci_mock.return_value = objects.InstancePCIRequests(requests=[request])
pci_requests = objects.InstancePCIRequests(
requests=[request],
instance_uuid=self.instance.uuid)
pci_mock.return_value = pci_requests
disk_used = self.instance.root_gb + self.instance.ephemeral_gb
expected = copy.deepcopy(_COMPUTE_NODE_FIXTURES[0])
@ -1414,7 +1431,7 @@ class TestInstanceClaim(BaseTestCase):
"free_ram_mb": expected.memory_mb - self.instance.memory_mb,
'running_vms': 1,
'vcpus_used': 1,
'pci_device_pools': pci_pools,
'pci_device_pools': objects.PciDevicePoolList(),
'stats': {
'io_workload': 0,
'num_instances': 1,
@ -1429,9 +1446,7 @@ class TestInstanceClaim(BaseTestCase):
with mock.patch.object(self.instance, 'save'):
self.rt.instance_claim(self.ctx, self.instance, None)
update_mock.assert_called_once_with(self.elevated)
pci_manager_mock.assert_called_once_with(mock.ANY, # context...
pci_mock.return_value,
None)
pci_stats_mock.assert_called_once_with([request])
self.assertTrue(obj_base.obj_equal_prims(expected,
self.rt.compute_node))

View File

@ -1266,13 +1266,22 @@ class _TestInstanceObject(object):
def test_apply_revert_migration_context(self):
inst = instance.Instance(context=self.context, uuid=uuids.instance,
numa_topology=None)
numa_topology=None, pci_requests=None,
pci_devices=None)
inst.migration_context = test_mig_ctxt.get_fake_migration_context_obj(
self.context)
inst.apply_migration_context()
self.assertIsInstance(inst.numa_topology, objects.InstanceNUMATopology)
attrs_type = {'numa_topology': objects.InstanceNUMATopology,
'pci_requests': objects.InstancePCIRequests,
'pci_devices': objects.PciDeviceList}
for attr_name in instance._MIGRATION_CONTEXT_ATTRS:
value = getattr(inst, attr_name)
self.assertIsInstance(value, attrs_type[attr_name])
inst.revert_migration_context()
self.assertIsNone(inst.numa_topology)
for attr_name in instance._MIGRATION_CONTEXT_ATTRS:
value = getattr(inst, attr_name)
self.assertIsNone(value)
def test_drop_migration_context(self):
inst = instance.Instance(context=self.context, uuid=uuids.instance)
@ -1292,15 +1301,29 @@ class _TestInstanceObject(object):
fake_obj_numa_topology.obj_clone())
numa_topology.cells[0].memory = 1024
numa_topology.cells[1].memory = 1024
pci_requests = objects.InstancePCIRequests(requests=[
objects.InstancePCIRequest(count=1, spec=[])])
pci_devices = pci_device.PciDeviceList()
inst = instance.Instance(context=self.context, uuid=uuids.instance,
numa_topology=numa_topology)
numa_topology=numa_topology,
pci_requests=pci_requests,
pci_devices=pci_devices)
expected_objs = {'numa_topology': numa_topology,
'pci_requests': pci_requests,
'pci_devices': pci_devices}
inst.migration_context = test_mig_ctxt.get_fake_migration_context_obj(
self.context)
with inst.mutated_migration_context():
self.assertIs(inst.numa_topology,
inst.migration_context.new_numa_topology)
self.assertIs(numa_topology, inst.numa_topology)
for attr_name in instance._MIGRATION_CONTEXT_ATTRS:
inst_value = getattr(inst, attr_name)
migration_context_value = (
getattr(inst.migration_context, 'new_' + attr_name))
self.assertIs(inst_value, migration_context_value)
for attr_name in instance._MIGRATION_CONTEXT_ATTRS:
inst_value = getattr(inst, attr_name)
self.assertIs(expected_objs[attr_name], inst_value)
def test_clear_numa_topology(self):
numa_topology = (test_instance_numa_topology.

View File

@ -29,6 +29,12 @@ fake_migration_context_obj.migration_id = 42
fake_migration_context_obj.new_numa_topology = (
test_instance_numa_topology.fake_obj_numa_topology.obj_clone())
fake_migration_context_obj.old_numa_topology = None
fake_migration_context_obj.new_pci_devices = objects.PciDeviceList()
fake_migration_context_obj.old_pci_devices = None
fake_migration_context_obj.new_pci_requests = (
objects.InstancePCIRequests(requests=[
objects.InstancePCIRequest(count=123, spec=[])]))
fake_migration_context_obj.old_pci_requests = None
fake_db_context = {
'created_at': None,
@ -48,6 +54,7 @@ def get_fake_migration_context_obj(ctxt):
class _TestMigrationContext(object):
def _test_get_by_instance_uuid(self, db_data):
mig_context = objects.MigrationContext.get_by_instance_uuid(
self.context, fake_db_context['instance_uuid'])
@ -65,6 +72,14 @@ class _TestMigrationContext(object):
mig_context.new_numa_topology.__class__)
self.assertIsInstance(expected_mig_context.old_numa_topology,
mig_context.old_numa_topology.__class__)
self.assertIsInstance(expected_mig_context.new_pci_devices,
mig_context.new_pci_devices.__class__)
self.assertIsInstance(expected_mig_context.old_pci_devices,
mig_context.old_pci_devices.__class__)
self.assertIsInstance(expected_mig_context.new_pci_requests,
mig_context.new_pci_requests.__class__)
self.assertIsInstance(expected_mig_context.old_pci_requests,
mig_context.old_pci_requests.__class__)
else:
self.assertIsNone(mig_context)

View File

@ -1158,7 +1158,7 @@ object_data = {
'KeyPair': '1.4-1244e8d1b103cc69d038ed78ab3a8cc6',
'KeyPairList': '1.2-58b94f96e776bedaf1e192ddb2a24c4e',
'Migration': '1.4-17979b9f2ae7f28d97043a220b2a8350',
'MigrationContext': '1.0-d8c2f10069e410f639c49082b5932c92',
'MigrationContext': '1.1-9fb17b0b521370957a884636499df52d',
'MigrationList': '1.3-55595bfc1a299a5962614d0821a3567e',
'MonitorMetric': '1.1-53b1db7c4ae2c531db79761e7acc52ba',
'MonitorMetricList': '1.1-15ecf022a68ddbb8c2a6739cfc9f8f5e',

View File

@ -124,7 +124,7 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
def _fake_pci_device_destroy(self, ctxt, node_id, address):
self.destroy_called += 1
def _create_pci_requests_object(self, mock_get, requests,
def _create_pci_requests_object(self, requests,
instance_uuid=None):
instance_uuid = instance_uuid or uuidsentinel.instance1
pci_reqs = []
@ -132,7 +132,7 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
pci_req_obj = objects.InstancePCIRequest(count=request['count'],
spec=request['spec'])
pci_reqs.append(pci_req_obj)
mock_get.return_value = objects.InstancePCIRequests(
return objects.InstancePCIRequests(
instance_uuid=instance_uuid,
requests=pci_reqs)
@ -306,11 +306,11 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self.assertEqual(vfs, pf.child_devices)
self.assertEqual(vfs[0].parent_device, pf)
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_set_hvdev_changed_stal(self, mock_get):
self._create_pci_requests_object(mock_get,
def test_set_hvdev_changed_stal(self):
pci_requests_obj = self._create_pci_requests_object(
[{'count': 1, 'spec': [{'vendor_id': 'v1'}]}])
self.tracker._claim_instance(None, mock_get.return_value, None)
self.tracker.claim_instance(mock.sentinel.context,
pci_requests_obj, None)
fake_pci_3 = dict(fake_pci, address='0000:00:00.2', vendor_id='v2')
fake_pci_devs = [copy.deepcopy(fake_pci), copy.deepcopy(fake_pci_2),
copy.deepcopy(fake_pci_3)]
@ -318,11 +318,10 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self.assertEqual(len(self.tracker.stale), 1)
self.assertEqual(self.tracker.stale['0000:00:00.2']['vendor_id'], 'v2')
@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.claim_instance(None, mock_get.return_value, None)
def test_update_pci_for_instance_active(self):
pci_requests_obj = self._create_pci_requests_object(fake_pci_requests)
self.tracker.claim_instance(mock.sentinel.context,
pci_requests_obj, None)
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)
@ -330,12 +329,12 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self.assertEqual(len(free_devs), 1)
self.assertEqual(free_devs[0].vendor_id, 'v')
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_update_pci_for_instance_fail(self, mock_get):
def test_update_pci_for_instance_fail(self):
pci_requests = copy.deepcopy(fake_pci_requests)
pci_requests[0]['count'] = 4
self._create_pci_requests_object(mock_get, pci_requests)
self.tracker.claim_instance(None, mock_get.return_value, None)
pci_requests_obj = self._create_pci_requests_object(pci_requests)
self.tracker.claim_instance(mock.sentinel.context,
pci_requests_obj, None)
self.assertEqual(len(self.tracker.claims[self.inst['uuid']]), 0)
devs = self.tracker.update_pci_for_instance(None,
self.inst,
@ -343,8 +342,7 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self.assertEqual(len(self.tracker.allocations[self.inst['uuid']]), 0)
self.assertIsNone(devs)
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_pci_claim_instance_with_numa(self, mock_get):
def test_pci_claim_instance_with_numa(self):
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)
@ -352,31 +350,32 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self.tracker._set_hvdevs(fake_devs_numa)
pci_requests = copy.deepcopy(fake_pci_requests)[:1]
pci_requests[0]['count'] = 2
self._create_pci_requests_object(mock_get, pci_requests)
pci_requests_obj = self._create_pci_requests_object(pci_requests)
self.inst.numa_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=1, cpuset=set([1, 2]), memory=512)])
self.tracker.claim_instance(None, mock_get.return_value,
self.tracker.claim_instance(mock.sentinel.context,
pci_requests_obj,
self.inst.numa_topology)
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_pci_claim_instance_with_numa_fail(self, mock_get):
self._create_pci_requests_object(mock_get, fake_pci_requests)
def test_pci_claim_instance_with_numa_fail(self):
pci_requests_obj = self._create_pci_requests_object(fake_pci_requests)
self.inst.numa_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=1, cpuset=set([1, 2]), memory=512)])
self.assertIsNone(self.tracker.claim_instance(
None, mock_get.return_value,
self.inst.numa_topology))
mock.sentinel.context,
pci_requests_obj,
self.inst.numa_topology))
@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.claim_instance(None, mock_get.return_value, None)
def test_update_pci_for_instance_deleted(self):
pci_requests_obj = self._create_pci_requests_object(fake_pci_requests)
self.tracker.claim_instance(mock.sentinel.context,
pci_requests_obj, None)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 1)
self.inst.vm_state = vm_states.DELETED
@ -387,25 +386,6 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
dev in self.tracker.pci_devs]),
set(['v', 'v1']))
@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)
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(free_devs[0].vendor_id, 'v')
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_update_pci_for_migration_out(self, mock_get):
self._create_pci_requests_object(mock_get, fake_pci_requests)
self.tracker.update_pci_for_migration(None, self.inst)
self.tracker.update_pci_for_migration(None, self.inst, sign=-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.object(objects.PciDevice, 'should_migrate_data',
return_value=False)
def test_save(self, migrate_mock):
@ -436,21 +416,22 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self.assertEqual(len(self.tracker.pci_devs), 2)
self.assertEqual(self.destroy_called, 1)
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_clean_usage(self, mock_get):
def test_clean_usage(self):
inst_2 = copy.copy(self.inst)
inst_2.uuid = uuidsentinel.instance2
migr = {'instance_uuid': 'uuid2', 'vm_state': vm_states.BUILDING}
orph = {'uuid': 'uuid3', 'vm_state': vm_states.BUILDING}
self._create_pci_requests_object(mock_get,
pci_requests_obj = self._create_pci_requests_object(
[{'count': 1, 'spec': [{'vendor_id': 'v'}]}])
self.tracker.claim_instance(None, mock_get.return_value, None)
self.tracker.claim_instance(mock.sentinel.context,
pci_requests_obj, None)
self.tracker.update_pci_for_instance(None, self.inst, sign=1)
self._create_pci_requests_object(mock_get,
pci_requests_obj = self._create_pci_requests_object(
[{'count': 1, 'spec': [{'vendor_id': 'v1'}]}],
instance_uuid=inst_2.uuid)
self.tracker.claim_instance(None, mock_get.return_value, None)
self.tracker.claim_instance(mock.sentinel.context,
pci_requests_obj, None)
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)
@ -463,37 +444,11 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
set([dev.vendor_id for dev in free_devs]),
set(['v', 'v1']))
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_clean_usage_claims(self, mock_get):
inst_2 = copy.copy(self.inst)
inst_2.uuid = uuidsentinel.instance2
migr = {'instance_uuid': 'uuid2', 'vm_state': vm_states.BUILDING}
orph = {'uuid': 'uuid3', 'vm_state': vm_states.BUILDING}
self._create_pci_requests_object(mock_get,
[{'count': 1, 'spec': [{'vendor_id': 'v'}]}])
self.tracker.claim_instance(None, mock_get.return_value, None)
self.tracker.update_pci_for_instance(None, self.inst, sign=1)
self._create_pci_requests_object(mock_get,
[{'count': 1, 'spec': [{'vendor_id': 'v1'}]}],
instance_uuid=inst_2.uuid)
self.tracker.update_pci_for_migration(None, inst_2)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 1)
self.tracker.clean_usage([self.inst], [migr], [orph])
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(len(free_devs), 2)
self.assertEqual(
set([dev.vendor_id for dev in free_devs]),
set(['v', 'v1']))
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_clean_usage_no_request_match_no_claims(self, mock_get):
def test_clean_usage_no_request_match_no_claims(self):
# Tests the case that there is no match for the request so the
# claims mapping is set to None for the instance when the tracker
# calls clean_usage.
self._create_pci_requests_object(mock_get, [])
self.tracker.update_pci_for_migration(None, instance=self.inst, sign=1)
self.tracker.update_pci_for_instance(None, self.inst, sign=1)
free_devs = self.tracker.pci_stats.get_free_devs()
self.assertEqual(3, len(free_devs))
self.tracker.clean_usage([], [], [])
@ -503,11 +458,11 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
set([dev.address for dev in free_devs]),
set(['0000:00:00.1', '0000:00:00.2', '0000:00:00.3']))
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance')
def test_free_devices(self, mock_get):
self._create_pci_requests_object(mock_get,
def test_free_devices(self):
pci_requests_obj = self._create_pci_requests_object(
[{'count': 1, 'spec': [{'vendor_id': 'v'}]}])
self.tracker.claim_instance(None, mock_get.return_value, None)
self.tracker.claim_instance(mock.sentinel.context,
pci_requests_obj, None)
self.tracker.update_pci_for_instance(None, self.inst, sign=1)
free_devs = self.tracker.pci_stats.get_free_devs()