objects: Store InstancePCIRequest.numa_policy in DB
In change I9360fe29908, we added the 'numa_policy' field to the 'InstancePCIRequest' object. Unfortunately we did not update the (de)serialization logic for the 'InstancePCIRequests' object, meaning this field was never saved to the database. As a result, claiming will always fail [1]. The resolution is simple - add the (de)serialization logic and tests to prevent regression. [1] https://github.com/openstack/nova/blob/18.0.0/nova/compute/resource_tracker.py#L214-L215 Change-Id: Id4d8ecb8fee46b21590ebcc62a2850030cef6508 Closes-Bug: #1805891
This commit is contained in:
parent
6304bcf781
commit
59d9463351
|
@ -90,6 +90,8 @@ class InstancePCIRequests(base.NovaObject,
|
|||
request_obj = InstancePCIRequest(
|
||||
count=request['count'], spec=request['spec'],
|
||||
alias_name=request['alias_name'], is_new=False,
|
||||
numa_policy=request.get('numa_policy',
|
||||
fields.PCINUMAAffinityPolicy.LEGACY),
|
||||
request_id=request['request_id'],
|
||||
requester_id=request.get('requester_id'))
|
||||
request_obj.obj_reset_changes()
|
||||
|
@ -142,6 +144,7 @@ class InstancePCIRequests(base.NovaObject,
|
|||
'spec': x.spec,
|
||||
'alias_name': x.alias_name,
|
||||
'is_new': x.is_new,
|
||||
'numa_policy': x.numa_policy,
|
||||
'request_id': x.request_id,
|
||||
'requester_id': x.requester_id} for x in self.requests]
|
||||
return jsonutils.dumps(blob)
|
||||
|
|
|
@ -26,27 +26,32 @@ CONF = cfg.CONF
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SRIOVServersTest(base.ServersTestBase):
|
||||
class _PCIServersTestBase(base.ServersTestBase):
|
||||
|
||||
vfs_alias_name = 'vfs'
|
||||
pfs_alias_name = 'pfs'
|
||||
|
||||
pci_passthrough_whitelist = [
|
||||
'{"vendor_id":"8086", "product_id":"1528"}',
|
||||
'{"vendor_id":"8086", "product_id":"1515"}',
|
||||
]
|
||||
# PFs will be removed from pools unless they are specifically
|
||||
# requested, so we explicitly request them with the 'device_type'
|
||||
# attribute
|
||||
pci_alias = [
|
||||
'{"vendor_id":"8086", "product_id":"1528", "name":"%s", '
|
||||
'"device_type":"%s"}' % (
|
||||
pfs_alias_name, fields.PciDeviceType.SRIOV_PF),
|
||||
'{"vendor_id":"8086", "product_id":"1515", "name":"%s"}' % (
|
||||
vfs_alias_name),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
white_list = ['{"vendor_id":"8086","product_id":"1528"}',
|
||||
'{"vendor_id":"8086","product_id":"1515"}']
|
||||
self.flags(passthrough_whitelist=white_list, group='pci')
|
||||
self.flags(passthrough_whitelist=self.pci_passthrough_whitelist,
|
||||
alias=self.pci_alias,
|
||||
group='pci')
|
||||
|
||||
# PFs will be removed from pools, unless these has been specifically
|
||||
# requested. This is especially needed in cases where PFs and VFs have
|
||||
# the same vendor/product id
|
||||
pci_alias = ['{"vendor_id":"8086", "product_id":"1528", "name":"%s",'
|
||||
' "device_type":"%s"}' % (self.pfs_alias_name,
|
||||
fields.PciDeviceType.SRIOV_PF),
|
||||
'{"vendor_id":"8086", "product_id":"1515", "name":"%s"}' %
|
||||
self.vfs_alias_name]
|
||||
self.flags(alias=pci_alias, group='pci')
|
||||
|
||||
super(SRIOVServersTest, self).setUp()
|
||||
super(_PCIServersTestBase, self).setUp()
|
||||
|
||||
self.compute_started = False
|
||||
|
||||
|
@ -63,10 +68,12 @@ class SRIOVServersTest(base.ServersTestBase):
|
|||
|
||||
def _setup_scheduler_service(self):
|
||||
# Enable the 'NUMATopologyFilter', 'PciPassthroughFilter'
|
||||
enabled_filters = CONF.filter_scheduler.enabled_filters + [
|
||||
'NUMATopologyFilter', 'PciPassthroughFilter']
|
||||
|
||||
self.flags(driver='filter_scheduler', group='scheduler')
|
||||
self.flags(enabled_filters=CONF.filter_scheduler.enabled_filters
|
||||
+ ['NUMATopologyFilter', 'PciPassthroughFilter'],
|
||||
group='filter_scheduler')
|
||||
self.flags(enabled_filters=enabled_filters, group='filter_scheduler')
|
||||
|
||||
return self.start_service('scheduler')
|
||||
|
||||
def _run_build_test(self, flavor_id, end_status='ACTIVE'):
|
||||
|
@ -103,6 +110,9 @@ class SRIOVServersTest(base.ServersTestBase):
|
|||
self.addCleanup(self._delete_server, created_server_id)
|
||||
return created_server
|
||||
|
||||
|
||||
class SRIOVServersTest(_PCIServersTestBase):
|
||||
|
||||
@mock.patch('nova.virt.libvirt.LibvirtDriver._create_image')
|
||||
def test_create_server_with_VF(self, img_mock):
|
||||
|
||||
|
@ -177,6 +187,9 @@ class SRIOVServersTest(base.ServersTestBase):
|
|||
self._run_build_test(flavor_id_vfs)
|
||||
self._run_build_test(flavor_id_pfs, end_status='ERROR')
|
||||
|
||||
|
||||
class PCIServersTest(_PCIServersTestBase):
|
||||
|
||||
@mock.patch('nova.virt.libvirt.LibvirtDriver._create_image')
|
||||
def test_create_server_with_pci_dev_and_numa(self, img_mock):
|
||||
"""Verifies that an instance can be booted with cpu pinning and with an
|
||||
|
@ -190,11 +203,11 @@ class SRIOVServersTest(base.ServersTestBase):
|
|||
fake_connection = self._get_connection(host_info, pci_info)
|
||||
self.mock_conn.return_value = fake_connection
|
||||
|
||||
# Create a flavor
|
||||
extra_spec = {"pci_passthrough:alias": "%s:1" % self.pfs_alias_name,
|
||||
'hw:numa_nodes': '1',
|
||||
# create a flavor
|
||||
extra_spec = {
|
||||
'hw:cpu_policy': 'dedicated',
|
||||
'hw:cpu_thread_policy': 'prefer'}
|
||||
'pci_passthrough:alias': '%s:1' % self.pfs_alias_name,
|
||||
}
|
||||
flavor_id = self._create_flavor(extra_spec=extra_spec)
|
||||
|
||||
self._run_build_test(flavor_id)
|
||||
|
@ -212,15 +225,64 @@ class SRIOVServersTest(base.ServersTestBase):
|
|||
fake_connection = self._get_connection(host_info, pci_info)
|
||||
self.mock_conn.return_value = fake_connection
|
||||
|
||||
# Create a flavor
|
||||
extra_spec_vm = {'hw:cpu_policy': 'dedicated',
|
||||
'hw:numa_node': '1'}
|
||||
extra_spec = {'pci_passthrough:alias': '%s:1' % self.pfs_alias_name,
|
||||
'hw:numa_nodes': '1',
|
||||
# boot one instance with no PCI device to "fill up" NUMA node 0
|
||||
extra_spec = {
|
||||
'hw:cpu_policy': 'dedicated',
|
||||
'hw:cpu_thread_policy': 'prefer'}
|
||||
vm_flavor_id = self._create_flavor(vcpu=4, extra_spec=extra_spec_vm)
|
||||
pf_flavor_id = self._create_flavor(extra_spec=extra_spec)
|
||||
}
|
||||
flavor_id = self._create_flavor(vcpu=4, extra_spec=extra_spec)
|
||||
|
||||
self._run_build_test(vm_flavor_id)
|
||||
self._run_build_test(pf_flavor_id, end_status='ERROR')
|
||||
self._run_build_test(flavor_id)
|
||||
|
||||
# now boot one with a PCI device, which should fail to boot
|
||||
extra_spec['pci_passthrough:alias'] = '%s:1' % self.pfs_alias_name
|
||||
flavor_id = self._create_flavor(extra_spec=extra_spec)
|
||||
|
||||
self._run_build_test(flavor_id, end_status='ERROR')
|
||||
|
||||
|
||||
class PCIServersWithNUMAPoliciesTest(_PCIServersTestBase):
|
||||
|
||||
# PFs will be removed from pools unless they are specifically
|
||||
# requested, so we explicitly request them with the 'device_type'
|
||||
# attribute
|
||||
pci_alias = [
|
||||
'{"vendor_id":"8086", "product_id":"1528", "name":"%s", '
|
||||
'"device_type":"%s", "numa_policy":"%s"}' % (
|
||||
_PCIServersTestBase.pfs_alias_name,
|
||||
fields.PciDeviceType.SRIOV_PF,
|
||||
fields.PCINUMAAffinityPolicy.PREFERRED
|
||||
),
|
||||
'{"vendor_id":"8086", "product_id":"1515", "name":"%s"}' % (
|
||||
_PCIServersTestBase.vfs_alias_name),
|
||||
]
|
||||
|
||||
@mock.patch('nova.virt.libvirt.LibvirtDriver._create_image')
|
||||
def test_create_server_with_pci_dev_and_numa(self, img_mock):
|
||||
"""Validate behavior of 'preferred' PCI NUMA policy.
|
||||
|
||||
This test ensures that it *is* possible to allocate CPU and memory
|
||||
resources from one NUMA node and a PCI device from another *if* PCI
|
||||
NUMA policies are in use.
|
||||
"""
|
||||
|
||||
host_info = fakelibvirt.NUMAHostInfo(cpu_nodes=2, cpu_sockets=1,
|
||||
cpu_cores=2, cpu_threads=2,
|
||||
kB_mem=15740000)
|
||||
pci_info = fakelibvirt.HostPciSRIOVDevicesInfo(num_pfs=1, numa_node=0)
|
||||
fake_connection = self._get_connection(host_info, pci_info)
|
||||
self.mock_conn.return_value = fake_connection
|
||||
|
||||
# boot one instance with no PCI device to "fill up" NUMA node 0
|
||||
extra_spec = {
|
||||
'hw:cpu_policy': 'dedicated',
|
||||
}
|
||||
flavor_id = self._create_flavor(vcpu=4, extra_spec=extra_spec)
|
||||
|
||||
self._run_build_test(flavor_id)
|
||||
|
||||
# now boot one with a PCI device, which should succeed thanks to the
|
||||
# use of the PCI policy
|
||||
extra_spec['pci_passthrough:alias'] = '%s:1' % self.pfs_alias_name
|
||||
flavor_id = self._create_flavor(extra_spec=extra_spec)
|
||||
|
||||
self._run_build_test(flavor_id)
|
||||
|
|
|
@ -574,7 +574,7 @@ class _TestInstanceObject(object):
|
|||
expected_json = ('[{"count": 1, "alias_name": null, "is_new": false,'
|
||||
'"request_id": null, "requester_id": null,'
|
||||
'"spec": [{"vendor_id": "8086", '
|
||||
'"product_id": "1502"}]}]')
|
||||
'"product_id": "1502"}], "numa_policy": null}]')
|
||||
|
||||
inst = objects.Instance()
|
||||
inst = objects.Instance._from_db_object(self.context, inst,
|
||||
|
|
|
@ -32,12 +32,14 @@ fake_pci_requests = [
|
|||
'device_id': '1502'}],
|
||||
'alias_name': 'alias_1',
|
||||
'is_new': False,
|
||||
'numa_policy': 'preferred',
|
||||
'request_id': FAKE_REQUEST_UUID},
|
||||
{'count': 2,
|
||||
'spec': [{'vendor_id': '6502',
|
||||
'device_id': '07B5'}],
|
||||
'alias_name': 'alias_2',
|
||||
'is_new': True,
|
||||
'numa_policy': 'preferred',
|
||||
'request_id': FAKE_REQUEST_UUID,
|
||||
'requester_id': uuids.requester_id},
|
||||
]
|
||||
|
@ -71,6 +73,8 @@ class _TestInstancePCIRequests(object):
|
|||
request.count)
|
||||
self.assertEqual(fake_pci_requests[index]['spec'],
|
||||
[dict(x.items()) for x in request.spec])
|
||||
self.assertEqual(fake_pci_requests[index]['numa_policy'],
|
||||
request.numa_policy)
|
||||
|
||||
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid')
|
||||
def test_get_by_instance_current(self, mock_get):
|
||||
|
@ -118,6 +122,7 @@ class _TestInstancePCIRequests(object):
|
|||
self.assertEqual(FAKE_UUID, req.instance_uuid)
|
||||
self.assertEqual(2, len(req.requests))
|
||||
self.assertEqual('alias_1', req.requests[0].alias_name)
|
||||
self.assertEqual('preferred', req.requests[0].numa_policy)
|
||||
self.assertIsNone(None, req.requests[0].requester_id)
|
||||
self.assertEqual(uuids.requester_id, req.requests[1].requester_id)
|
||||
|
||||
|
|
Loading…
Reference in New Issue