Skip to content

Commit b5dffed

Browse files
committed
Validate [pci]alias at service startup
Both nova-api and nova-compute depends on the [pci]alias configuration. These services loaded and validated the config lazily when it was needed. This can late and hard to troubleshoot failures during instance lifecycle operations due to simple config errors. So this patch adds an early load of this config to nova-api and nova-compute. Related-Bug: #2102038 Related-Bug: #2111440 Change-Id: I5d5dc912ca24979067984c7cb53ceaded7daf236 (cherry picked from commit ae064ca)
1 parent 2ca6c93 commit b5dffed

6 files changed

Lines changed: 43 additions & 12 deletions

File tree

nova/api/openstack/wsgi_app.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from nova import context
2727
from nova import exception
2828
from nova import objects
29+
from nova.pci import request
2930
from nova import service
3031
from nova import utils
3132
from nova import version
@@ -51,6 +52,11 @@ def _get_config_files(env=None):
5152

5253

5354
def _setup_service(host, name):
55+
56+
# NOTE(gibi): validate the [pci]alias config early to avoid late failures
57+
# at instance creation due to config errors.
58+
request.get_alias_from_config()
59+
5460
try:
5561
utils.raise_if_old_compute()
5662
except exception.TooOldComputeService as e:

nova/compute/manager.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,10 @@ def init_host(self, service_ref):
16211621
# if the configuration is wrong.
16221622
whitelist.Whitelist(CONF.pci.device_spec)
16231623

1624+
# NOTE(gibi): validate the [pci]alias config early to avoid late
1625+
# failures at instance lifecycle operations due to config errors.
1626+
pci_req_module.get_alias_from_config()
1627+
16241628
nova.conf.neutron.register_dynamic_opts(CONF)
16251629
# Even if only libvirt uses them, make it available for all drivers
16261630
nova.conf.devices.register_dynamic_opts(CONF)

nova/pci/request.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def _validate_aliases(aliases):
173173
_validate_required_ids(aliases)
174174

175175

176-
def _get_alias_from_config() -> Alias:
176+
def get_alias_from_config() -> Alias:
177177
"""Parse and validate PCI aliases from the nova config.
178178
179179
:returns: A dictionary where the keys are alias names and the values are
@@ -237,7 +237,7 @@ def _translate_alias_to_requests(
237237
alias_spec: str, affinity_policy: ty.Optional[str] = None,
238238
) -> ty.List['objects.InstancePCIRequest']:
239239
"""Generate complete pci requests from pci aliases in extra_spec."""
240-
pci_aliases = _get_alias_from_config()
240+
pci_aliases = get_alias_from_config()
241241

242242
pci_requests: ty.List[objects.InstancePCIRequest] = []
243243
for name, count in [spec.split(':') for spec in alias_spec.split(',')]:

nova/tests/unit/api/openstack/test_wsgi_app.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import fixtures
1717
from oslo_config import fixture as config_fixture
18+
from oslo_serialization import jsonutils
1819
from oslotest import base
1920

2021
from nova.api.openstack import wsgi_app
@@ -127,6 +128,14 @@ def test_setup_service_version_workaround(self, mock_check_old, mock_get):
127128
group='workarounds')
128129
wsgi_app._setup_service('myhost', 'api')
129130

131+
def test_setup_service_pci_alias_validation(self):
132+
wsgi_app.CONF.set_override(
133+
'alias', jsonutils.dumps({'name': 'foo'}),
134+
group='pci')
135+
self.assertRaises(
136+
exception.PciInvalidAlias,
137+
wsgi_app._setup_service, 'myhost', 'api')
138+
130139
def test__get_config_files_empty_env(self):
131140
env = {}
132141
result = wsgi_app._get_config_files(env)

nova/tests/unit/compute/test_compute_mgr.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6954,6 +6954,18 @@ def test_init_host_pci_device_spec_validation_failure(self):
69546954
self.assertRaises(exception.PciDeviceInvalidDeviceName,
69556955
self.compute.init_host, None)
69566956

6957+
def test_init_host_pci_alias_validation_failure(self):
6958+
# Tests that we fail init_host if the pci.alias is
6959+
# configured incorrectly.
6960+
self.flags(
6961+
alias=[
6962+
jsonutils.dumps({'name': 'foo'})
6963+
],
6964+
group='pci'
6965+
)
6966+
self.assertRaises(
6967+
exception.PciInvalidAlias, self.compute.init_host, None)
6968+
69576969
@mock.patch('nova.compute.manager.ComputeManager._instance_update')
69586970
def test_error_out_instance_on_exception_not_implemented_err(self,
69596971
inst_update_mock):

nova/tests/unit/pci/test_request.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def setUp(self):
8181

8282
def test_get_alias_from_config_valid(self):
8383
self.flags(alias=[_fake_alias1], group='pci')
84-
result = request._get_alias_from_config()
84+
result = request.get_alias_from_config()
8585
expected_result = (
8686
'legacy',
8787
[{
@@ -103,7 +103,7 @@ def test_get_alias_from_config_valid_multispec(self):
103103
})
104104

105105
self.flags(alias=[_fake_alias1, _fake_alias], group='pci')
106-
result = request._get_alias_from_config()
106+
result = request.get_alias_from_config()
107107
expected_result = (
108108
'legacy',
109109
[{
@@ -133,7 +133,7 @@ def test_get_alias_from_config_multispec_rejected_pci_in_placement(self):
133133
self.flags(alias=[_fake_alias1, _fake_alias], group='pci')
134134

135135
ex = self.assertRaises(
136-
exception.PciInvalidAlias, request._get_alias_from_config)
136+
exception.PciInvalidAlias, request.get_alias_from_config)
137137
self.assertEqual(
138138
"The PCI alias(es) QuickAssist have multiple specs but "
139139
"[filter_scheduler]pci_in_placement is True. The PCI in Placement "
@@ -146,7 +146,7 @@ def _test_get_alias_from_config_invalid(self, alias):
146146
self.flags(alias=[alias], group='pci')
147147
self.assertRaises(
148148
exception.PciInvalidAlias,
149-
request._get_alias_from_config)
149+
request.get_alias_from_config)
150150

151151
def test_get_alias_from_config_invalid_device_type(self):
152152
fake_alias = jsonutils.dumps({
@@ -215,7 +215,7 @@ def test_get_alias_from_config_valid_numa_policy(self):
215215
"numa_policy": policy,
216216
})
217217
self.flags(alias=[fake_alias], group='pci')
218-
aliases = request._get_alias_from_config()
218+
aliases = request.get_alias_from_config()
219219
self.assertIsNotNone(aliases)
220220
self.assertIn("xxx", aliases)
221221
self.assertEqual(policy, aliases["xxx"][0])
@@ -228,7 +228,7 @@ def test_get_alias_from_config_valid_rc_and_traits(self):
228228
})
229229
self.flags(pci_in_placement=True, group='filter_scheduler')
230230
self.flags(alias=[fake_alias], group='pci')
231-
aliases = request._get_alias_from_config()
231+
aliases = request.get_alias_from_config()
232232
self.assertIsNotNone(aliases)
233233
self.assertIn("xxx", aliases)
234234
self.assertEqual(
@@ -256,7 +256,7 @@ def test_get_alias_from_config_conflicting_device_type(self):
256256
self.flags(alias=[fake_alias_a, fake_alias_b], group='pci')
257257
self.assertRaises(
258258
exception.PciInvalidAlias,
259-
request._get_alias_from_config)
259+
request.get_alias_from_config)
260260

261261
def test_get_alias_from_config_conflicting_numa_policy(self):
262262
"""Check behavior when numa_policy conflicts occur."""
@@ -277,7 +277,7 @@ def test_get_alias_from_config_conflicting_numa_policy(self):
277277
self.flags(alias=[fake_alias_a, fake_alias_b], group='pci')
278278
self.assertRaises(
279279
exception.PciInvalidAlias,
280-
request._get_alias_from_config)
280+
request.get_alias_from_config)
281281

282282
def test_get_alias_from_config_missing_ids(self):
283283
a1 = jsonutils.dumps({
@@ -304,7 +304,7 @@ def test_get_alias_from_config_missing_ids(self):
304304
self.flags(alias=[a1, a2, a3, a4, a5], group='pci')
305305

306306
ex = self.assertRaises(
307-
exception.PciInvalidAlias, request._get_alias_from_config)
307+
exception.PciInvalidAlias, request.get_alias_from_config)
308308
self.assertEqual(
309309
"The PCI alias(es) a1,a2,a3,a4 does not have vendor_id and "
310310
"product_id fields set.",
@@ -336,7 +336,7 @@ def test_get_alias_from_config_missing_ids_or_rc_pci_in_placement(self):
336336
self.flags(alias=[a1, a2, a3, a4, a5], group='pci')
337337

338338
ex = self.assertRaises(
339-
exception.PciInvalidAlias, request._get_alias_from_config)
339+
exception.PciInvalidAlias, request.get_alias_from_config)
340340
self.assertEqual(
341341
"The PCI alias(es) a1,a2,a3 does not have vendor_id and "
342342
"product_id fields set or resource_class field set.",

0 commit comments

Comments
 (0)