-
Bug
-
Resolution: Unresolved
-
Normal
-
None
-
None
-
0
-
False
-
-
False
-
?
-
rhos-workloads-evolution
-
None
-
-
-
-
Moderate
When using unified limits with PCI-in-placement (`[filter_scheduler]pci_in_placement=True`), the quota check does NOT include PCI device resource classes from the flavor's `pci_passthrough:alias` extra spec. This allows users to exceed their PCI device quota limits (e.g., `class:CUSTOM_GPU`) because the unified limits check only considers standard resources like VCPU, MEMORY_MB, and DISK_GB.
-
-
- Affected Versions
-
- All versions with unified limits and PCI-in-placement support (Victoria+)
-
-
- Configuration Required
-
```ini
[quota]
driver = nova.quota.UnifiedLimitsDriver
[filter_scheduler]
pci_in_placement = True
[pci]
device_spec = [
]
alias = [
]
```
With Keystone unified limits configured:
```
class:CUSTOM_GPU = 1 # Limit to 1 GPU per project
```
—
-
- Steps to Reproduce
1. Configure Nova with unified limits quota driver and PCI-in-placement enabled
2. Configure PCI devices with a custom resource class (e.g., `gpu` → `CUSTOM_GPU`)
3. Configure a PCI alias for the resource class
4. Set a unified limit for the PCI resource class (e.g., `class:CUSTOM_GPU = 1`)
5. Create a flavor with `pci_passthrough:alias = a-gpu:2` (requests 2 GPUs)
6. Attempt to create a server with this flavor
—
-
- Expected Behavior
Server creation should fail with HTTP 403 Forbidden, with an error message indicating that the `class:CUSTOM_GPU` quota limit would be exceeded:
```
OverQuota: Resource class:CUSTOM_GPU is over limit of 1 due to usage 0 and delta 2
```
-
- Actual Behavior
Server creation succeeds, even though it requests 2 GPUs while the project limit is 1. The quota check does not recognize the PCI resource class requirement from the flavor.
-
- Root Cause Analysis
The bug is in `nova/scheduler/utils.py` in the `_get_resources()` function (called by `resources_for_limits()`).
*Problematic code path:*
```python
def _get_resources(flavor, is_bfv):
req_spec = objects.RequestSpec(flavor=flavor, is_bfv=is_bfv)
res_req = ResourceRequest.from_request_spec(req_spec)
return res_req.merged_resources()
```
This creates a minimal `RequestSpec` with only `flavor` and `is_bfv`. It does NOT:
1. Extract PCI requests from the flavor using `get_pci_requests_from_flavor()`
2. Convert PCI requests to placement request groups using `generate_request_groups_from_pci_requests()`
Without these steps, `ResourceRequest.from_request_spec()` never sees the PCI resource requirements, so `merged_resources()` returns only the standard resources (VCPU, MEMORY_MB, DISK_GB).
this also affect port and cyborg resource requests for a similar reason we are not constructing a fully request spec.