Support both list and dict for pci_passthrough_whitelist
In Icehouse, pci_passthrough_whitelist is a json docstring that
encodes a list. In Juno, it is a json docstring that encodes
a dict. This patch adds the list support back to
pci_passthrough_whitelist, and both list and dict are now supported.
(cherry picked from commit bb7bfd313c)
Conflicts:
nova/pci/pci_whitelist.py
nova/tests/pci/test_pci_devspec.py
Because juno imports module as pci_devspec since
kilo as devspec.
Closes-Bug: 1383345
Change-Id: I523cfb756a09c75e4f60015adadb3a1403298cd3
This commit is contained in:
@@ -15,7 +15,6 @@ import ast
|
||||
import re
|
||||
|
||||
from nova import exception
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova.pci import pci_utils
|
||||
|
||||
MAX_VENDOR_ID = 0xFFFF
|
||||
@@ -128,16 +127,15 @@ class PciAddress(object):
|
||||
|
||||
class PciDeviceSpec(object):
|
||||
def __init__(self, dev_spec):
|
||||
self.dev_spec = dev_spec
|
||||
self.tags = dev_spec
|
||||
self._init_dev_details()
|
||||
self.dev_count = 0
|
||||
|
||||
def _init_dev_details(self):
|
||||
details = jsonutils.loads(self.dev_spec)
|
||||
self.vendor_id = details.pop("vendor_id", ANY)
|
||||
self.product_id = details.pop("product_id", ANY)
|
||||
self.address = details.pop("address", None)
|
||||
self.dev_name = details.pop("devname", None)
|
||||
self.vendor_id = self.tags.pop("vendor_id", ANY)
|
||||
self.product_id = self.tags.pop("product_id", ANY)
|
||||
self.address = self.tags.pop("address", None)
|
||||
self.dev_name = self.tags.pop("devname", None)
|
||||
|
||||
self.vendor_id = self.vendor_id.strip()
|
||||
get_pci_dev_info(self, 'vendor_id', MAX_VENDOR_ID, '%04x')
|
||||
@@ -156,7 +154,6 @@ class PciDeviceSpec(object):
|
||||
self.address = "*:*:*.*"
|
||||
|
||||
self.address = PciAddress(self.address, pf)
|
||||
self.tags = details
|
||||
|
||||
def match(self, dev_dict):
|
||||
conditions = [
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova.openstack.common import log as logging
|
||||
from nova.pci import pci_devspec
|
||||
|
||||
@@ -46,8 +49,26 @@ class PciHostDevicesWhiteList(object):
|
||||
"""Parse and validate the pci whitelist from the nova config."""
|
||||
specs = []
|
||||
for jsonspec in whitelists:
|
||||
spec = pci_devspec.PciDeviceSpec(jsonspec)
|
||||
specs.append(spec)
|
||||
try:
|
||||
dev_spec = jsonutils.loads(jsonspec)
|
||||
except ValueError:
|
||||
raise exception.PciConfigInvalidWhitelist(
|
||||
reason=_("Invalid entry: '%s'") % jsonspec)
|
||||
if isinstance(dev_spec, dict):
|
||||
dev_spec = [dev_spec]
|
||||
elif not isinstance(dev_spec, list):
|
||||
raise exception.PciConfigInvalidWhitelist(
|
||||
reason=_("Invalid entry: '%s'; "
|
||||
"Expecting list or dict") % jsonspec)
|
||||
|
||||
for ds in dev_spec:
|
||||
if not isinstance(ds, dict):
|
||||
raise exception.PciConfigInvalidWhitelist(
|
||||
reason=_("Invalid entry: '%s'; "
|
||||
"Expecting dict") % ds)
|
||||
|
||||
spec = pci_devspec.PciDeviceSpec(ds)
|
||||
specs.append(spec)
|
||||
|
||||
return specs
|
||||
|
||||
|
||||
@@ -27,26 +27,25 @@ dev = {"vendor_id": "8086",
|
||||
|
||||
class PciAddressTestCase(test.NoDBTestCase):
|
||||
def test_wrong_address(self):
|
||||
pci_info = ('{"vendor_id": "8086", "address": "*: *: *.6",' +
|
||||
'"product_id": "5057", "physical_network": "hr_net"}')
|
||||
pci_info = {"vendor_id": "8086", "address": "*: *: *.6",
|
||||
"product_id": "5057", "physical_network": "hr_net"}
|
||||
pci = pci_devspec.PciDeviceSpec(pci_info)
|
||||
self.assertFalse(pci.match(dev))
|
||||
|
||||
def test_address_too_big(self):
|
||||
pci_info = ('{"address": "0000:0a:0b:00.5", ' +
|
||||
'"physical_network": "hr_net"}')
|
||||
pci_info = {"address": "0000:0a:0b:00.5",
|
||||
"physical_network": "hr_net"}
|
||||
self.assertRaises(exception.PciDeviceWrongAddressFormat,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
|
||||
def test_address_invalid_character(self):
|
||||
pci_info = '{"address": "0000:h4.12:6", "physical_network": "hr_net"}'
|
||||
pci_info = {"address": "0000:h4.12:6", "physical_network": "hr_net"}
|
||||
self.assertRaises(exception.PciDeviceWrongAddressFormat,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
|
||||
def test_max_func(self):
|
||||
pci_info = (('{"address": "0000:0a:00.%s", ' +
|
||||
'"physical_network": "hr_net"}') %
|
||||
(pci_devspec.MAX_FUNC + 1))
|
||||
pci_info = {"address": "0000:0a:00.%s" % (pci_devspec.MAX_FUNC + 1),
|
||||
"physical_network": "hr_net"}
|
||||
exc = self.assertRaises(exception.PciDeviceInvalidAddressField,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
msg = ('Invalid PCI Whitelist: '
|
||||
@@ -55,8 +54,8 @@ class PciAddressTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(msg, unicode(exc))
|
||||
|
||||
def test_max_domain(self):
|
||||
pci_info = ('{"address": "%x:0a:00.5", "physical_network":"hr_net"}'
|
||||
% (pci_devspec.MAX_DOMAIN + 1))
|
||||
pci_info = {"address": "%x:0a:00.5" % (pci_devspec.MAX_DOMAIN + 1),
|
||||
"physical_network": "hr_net"}
|
||||
exc = self.assertRaises(exception.PciConfigInvalidWhitelist,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
msg = ('Invalid PCI devices Whitelist config invalid domain %x'
|
||||
@@ -64,8 +63,8 @@ class PciAddressTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(msg, unicode(exc))
|
||||
|
||||
def test_max_bus(self):
|
||||
pci_info = ('{"address": "0000:%x:00.5", "physical_network":"hr_net"}'
|
||||
% (pci_devspec.MAX_BUS + 1))
|
||||
pci_info = {"address": "0000:%x:00.5" % (pci_devspec.MAX_BUS + 1),
|
||||
"physical_network": "hr_net"}
|
||||
exc = self.assertRaises(exception.PciConfigInvalidWhitelist,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
msg = ('Invalid PCI devices Whitelist config invalid bus %x'
|
||||
@@ -73,8 +72,8 @@ class PciAddressTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(msg, unicode(exc))
|
||||
|
||||
def test_max_slot(self):
|
||||
pci_info = ('{"address": "0000:0a:%x.5", "physical_network":"hr_net"}'
|
||||
% (pci_devspec.MAX_SLOT + 1))
|
||||
pci_info = {"address": "0000:0a:%x.5" % (pci_devspec.MAX_SLOT + 1),
|
||||
"physical_network": "hr_net"}
|
||||
exc = self.assertRaises(exception.PciConfigInvalidWhitelist,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
msg = ('Invalid PCI devices Whitelist config invalid slot %x'
|
||||
@@ -82,12 +81,12 @@ class PciAddressTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(msg, unicode(exc))
|
||||
|
||||
def test_address_is_undefined(self):
|
||||
pci_info = '{"vendor_id":"8086", "product_id":"5057"}'
|
||||
pci_info = {"vendor_id": "8086", "product_id": "5057"}
|
||||
pci = pci_devspec.PciDeviceSpec(pci_info)
|
||||
self.assertTrue(pci.match(dev))
|
||||
|
||||
def test_partial_address(self):
|
||||
pci_info = '{"address":":0a:00.", "physical_network":"hr_net"}'
|
||||
pci_info = {"address": ":0a:00.", "physical_network": "hr_net"}
|
||||
pci = pci_devspec.PciDeviceSpec(pci_info)
|
||||
dev = {"vendor_id": "1137",
|
||||
"product_id": "0071",
|
||||
@@ -97,7 +96,7 @@ class PciAddressTestCase(test.NoDBTestCase):
|
||||
|
||||
@mock.patch('nova.pci.pci_utils.is_physical_function', return_value = True)
|
||||
def test_address_is_pf(self, mock_is_physical_function):
|
||||
pci_info = '{"address":"0000:0a:00.0", "physical_network":"hr_net"}'
|
||||
pci_info = {"address": "0000:0a:00.0", "physical_network": "hr_net"}
|
||||
pci = pci_devspec.PciDeviceSpec(pci_info)
|
||||
self.assertTrue(pci.match(dev))
|
||||
|
||||
@@ -107,63 +106,63 @@ class PciDevSpecTestCase(test.NoDBTestCase):
|
||||
super(PciDevSpecTestCase, self).setUp()
|
||||
|
||||
def test_spec_match(self):
|
||||
pci_info = ('{"vendor_id": "8086","address": "*: *: *.5",' +
|
||||
'"product_id": "5057", "physical_network": "hr_net"}')
|
||||
pci_info = {"vendor_id": "8086", "address": "*: *: *.5",
|
||||
"product_id": "5057", "physical_network": "hr_net"}
|
||||
pci = pci_devspec.PciDeviceSpec(pci_info)
|
||||
self.assertTrue(pci.match(dev))
|
||||
|
||||
def test_invalid_vendor_id(self):
|
||||
pci_info = ('{"vendor_id": "8087","address": "*: *: *.5", ' +
|
||||
'"product_id": "5057", "physical_network": "hr_net"}')
|
||||
pci_info = {"vendor_id": "8087", "address": "*: *: *.5",
|
||||
"product_id": "5057", "physical_network": "hr_net"}
|
||||
pci = pci_devspec.PciDeviceSpec(pci_info)
|
||||
self.assertFalse(pci.match(dev))
|
||||
|
||||
def test_vendor_id_out_of_range(self):
|
||||
pci_info = ('{"vendor_id": "80860", "address": "*:*:*.5", ' +
|
||||
'"product_id": "5057", "physical_network": "hr_net"}')
|
||||
pci_info = {"vendor_id": "80860", "address": "*:*:*.5",
|
||||
"product_id": "5057", "physical_network": "hr_net"}
|
||||
exc = self.assertRaises(exception.PciConfigInvalidWhitelist,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
self.assertEqual("Invalid PCI devices Whitelist config "
|
||||
"invalid vendor_id 80860", unicode(exc))
|
||||
|
||||
def test_invalid_product_id(self):
|
||||
pci_info = ('{"vendor_id": "8086","address": "*: *: *.5", ' +
|
||||
'"product_id": "5056", "physical_network": "hr_net"}')
|
||||
pci_info = {"vendor_id": "8086", "address": "*: *: *.5",
|
||||
"product_id": "5056", "physical_network": "hr_net"}
|
||||
pci = pci_devspec.PciDeviceSpec(pci_info)
|
||||
self.assertFalse(pci.match(dev))
|
||||
|
||||
def test_product_id_out_of_range(self):
|
||||
pci_info = ('{"vendor_id": "8086","address": "*:*:*.5", ' +
|
||||
'"product_id": "50570", "physical_network": "hr_net"}')
|
||||
pci_info = {"vendor_id": "8086", "address": "*:*:*.5",
|
||||
"product_id": "50570", "physical_network": "hr_net"}
|
||||
exc = self.assertRaises(exception.PciConfigInvalidWhitelist,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
self.assertEqual("Invalid PCI devices Whitelist config "
|
||||
"invalid product_id 50570", unicode(exc))
|
||||
|
||||
def test_devname_and_address(self):
|
||||
pci_info = ('{"devname": "eth0", "vendor_id":"8086", ' +
|
||||
'"address":"*:*:*.5", "physical_network": "hr_net"}')
|
||||
pci_info = {"devname": "eth0", "vendor_id": "8086",
|
||||
"address": "*:*:*.5", "physical_network": "hr_net"}
|
||||
self.assertRaises(exception.PciDeviceInvalidDeviceName,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
|
||||
@mock.patch('nova.pci.pci_utils.get_function_by_ifname',
|
||||
return_value = ("0000:0a:00.0", True))
|
||||
def test_by_name(self, mock_get_function_by_ifname):
|
||||
pci_info = '{"devname": "eth0", "physical_network": "hr_net"}'
|
||||
pci_info = {"devname": "eth0", "physical_network": "hr_net"}
|
||||
pci = pci_devspec.PciDeviceSpec(pci_info)
|
||||
self.assertTrue(pci.match(dev))
|
||||
|
||||
@mock.patch('nova.pci.pci_utils.get_function_by_ifname',
|
||||
return_value = (None, False))
|
||||
def test_invalid_name(self, mock_get_function_by_ifname):
|
||||
pci_info = '{"devname": "lo", "physical_network": "hr_net"}'
|
||||
pci_info = {"devname": "lo", "physical_network": "hr_net"}
|
||||
exc = self.assertRaises(exception.PciDeviceNotFoundById,
|
||||
pci_devspec.PciDeviceSpec, pci_info)
|
||||
self.assertEqual('PCI device lo not found', unicode(exc))
|
||||
|
||||
def test_pci_obj(self):
|
||||
pci_info = ('{"vendor_id": "8086","address": "*:*:*.5", ' +
|
||||
'"product_id": "5057", "physical_network": "hr_net"}')
|
||||
pci_info = {"vendor_id": "8086", "address": "*:*:*.5",
|
||||
"product_id": "5057", "physical_network": "hr_net"}
|
||||
|
||||
pci = pci_devspec.PciDeviceSpec(pci_info)
|
||||
pci_dev = {
|
||||
|
||||
@@ -36,6 +36,12 @@ class PciHostDevicesWhiteListTestCase(test.NoDBTestCase):
|
||||
parsed = pci_whitelist.PciHostDevicesWhiteList([white_list])
|
||||
self.assertEqual(1, len(parsed.specs))
|
||||
|
||||
def test_whitelist_list_format(self):
|
||||
white_list = '[{"product_id":"0001", "vendor_id":"8086"},'\
|
||||
'{"product_id":"0002", "vendor_id":"8086"}]'
|
||||
parsed = pci_whitelist.PciHostDevicesWhiteList([white_list])
|
||||
self.assertEqual(2, len(parsed.specs))
|
||||
|
||||
def test_whitelist_empty(self):
|
||||
parsed = pci_whitelist.PciHostDevicesWhiteList()
|
||||
self.assertFalse(parsed.device_assignable(dev_dict))
|
||||
|
||||
Reference in New Issue
Block a user