Skip to content

fix(ascend): reject over-capacity memory requests instead of defaulting to whole card - #2543

Closed
Neal006 wants to merge 3 commits into
Project-HAMi:masterfrom
Neal006:fix/ascend-over-capacity-memory
Closed

fix(ascend): reject over-capacity memory requests instead of defaulting to whole card#2543
Neal006 wants to merge 3 commits into
Project-HAMi:masterfrom
Neal006:fix/ascend-over-capacity-memory

Conversation

@Neal006

@Neal006 Neal006 commented Aug 10, 2026

Copy link
Copy Markdown

What type of PR is this?

/kind bug

What this PR does / why we need it:

trimMemory returns 0 when an Ascend memory request exceeds every template and the card capacity. GenerateResourceRequests dropped that zero, and the whole-card default below it reads a zero as "no memory requested", so an unsatisfiable request became a request for 100% of a card and scheduled.

MutateAdmission already rejects this on the limits path, but it returns early when the device count is absent from limits, so a pod declaring resources under requests only never reaches that check.

This carries the requested value through when trimMemory returns 0, so Fit rejects it. The value is clamped to MaxInt32 because the int32 narrowing at the return would otherwise wrap a large quantity back to zero and reintroduce the same bug.

Which issue(s) this PR fixes:

Fixes #2532

Special notes for your reviewer:

#2532 offers a second approach: make MutateAdmission fall back to requests so the existing rejection covers both shapes. That closes the bypass at its root, but it changes admission behaviour for every Ascend pod, so I took the narrower change here. Happy to switch to it or add it alongside if you prefer.

Verified with a regression case added to the existing Test_GenerateResourceRequests table. All pkg/device/... packages pass. I could not run --race or build pkg/device/nvidia locally because both need Linux, so CI covers those.

Per CONTRIBUTING.md, I used AI assistance while investigating and preparing this change. I verified the behaviour myself and can explain it.

Does this PR introduce a user-facing change?:

An Ascend memory request larger than the device capacity is now rejected instead of being silently scheduled as a whole-card request.

Summary by CodeRabbit

  • Bug Fixes
    • Preserved custom memory requests that exceed the configured memory capacity instead of replacing them with a whole-card allocation.
    • Capped exceptionally large memory requests at the supported maximum value.

…ng to whole card

trimMemory returns 0 when a request exceeds every template and the card
capacity. GenerateResourceRequests dropped that zero, and the whole-card
default a few lines below reads a zero as "no memory requested", so an
unsatisfiable request became a request for 100% of a card and scheduled.

MutateAdmission already rejects this on the limits path, but it returns
early when the device count is absent from limits, so a pod declaring
resources under requests only never reaches that check.

Carry the requested value through when trimMemory returns 0 so Fit
rejects it, clamped to MaxInt32 so the int32 narrowing cannot wrap it
back to zero.

Signed-off-by: Neal006 <nealdaftary0405@gmail.com>
Copilot AI lite review requested due to automatic review settings August 10, 2026 11:23
@hami-robot hami-robot Bot added kind/bug Something isn't working dco-signoff: yes labels Aug 10, 2026
@hami-robot

hami-robot Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Neal006
Once this PR has been reviewed and has the lgtm label, please assign shouren for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@hami-robot

hami-robot Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Welcome @Neal006! It looks like this is your first PR to Project-HAMi/HAMi 🎉

@hami-robot hami-robot Bot added the size/S label Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2e2d1a15-42d2-4aca-a8f4-27340757bf7c

📥 Commits

Reviewing files that changed from the base of the PR and between 9432a48 and cc01a6f.

📒 Files selected for processing (1)
  • pkg/device/ascend/device_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/device/ascend/device_test.go

📝 Walkthrough

Walkthrough

Ascend resource generation now preserves oversized memory requests with an int32 cap instead of converting them to whole-card allocations. Tests cover requests, limits, memory-factor scaling, and values above the int32 maximum.

Changes

Ascend memory request handling

Layer / File(s) Summary
Preserve and test oversized memory requests
pkg/device/ascend/device.go, pkg/device/ascend/device_test.go
GenerateResourceRequests preserves non-template memory values and caps values above math.MaxInt32. Tests cover requests, limits, memory-factor scaling, and oversized values.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: dsfans2014

Poem

A rabbit guards each memory plea,
Past card limits, values stay free.
math.MaxInt32 marks the line,
Tests keep every case in time.
Hop, hop—the request stays defined.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes rejecting over-capacity Ascend memory requests instead of treating them as whole-card requests.
Linked Issues check ✅ Passed The change preserves over-capacity memory requests so validation rejects them and adds regression coverage for requests and limits behavior.
Out of Scope Changes check ✅ Passed The code and test changes directly support the linked issue and its required regression coverage.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai
coderabbitai Bot requested a review from archlitchi August 10, 2026 11:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
pkg/device/ascend/device_test.go (1)

1214-1231: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add regression cases for the int32 cap and the Limits path.

The new case proves that 65536 is preserved, but that value fits in int32, so it does not test the new math.MaxInt32 clamp. It also exercises only Requests, while the PR objective requires the same behavior for Limits. Add one Limits-only over-capacity case and one request above math.MaxInt32 that expects Memreq == math.MaxInt32.

Example int32-boundary case
+		{
+			name: "resourcememoryname above int32 max is capped",
+			args: corev1.Container{
+				Resources: corev1.ResourceRequirements{
+					Requests: corev1.ResourceList{
+						"huawei.com/Ascend910A":        resource.MustParse("1"),
+						"huawei.com/Ascend910A-memory": resource.MustParse("2147483648"),
+					},
+				},
+			},
+			want: device.ContainerDeviceRequest{
+				Nums:             int32(1),
+				Type:             "Ascend910A",
+				Memreq:           int32(2147483647),
+				MemPercentagereq: int32(0),
+				Coresreq:         int32(0),
+			},
+		},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/device/ascend/device_test.go` around lines 1214 - 1231, Add regression
coverage in the device request test cases around the existing resourcememoryname
scenario: add a Limits-only case with an over-capacity memory request, and add a
Requests case whose memory value exceeds math.MaxInt32 and expects Memreq to
equal math.MaxInt32. Import or reference math.MaxInt32 consistently with the
test package’s conventions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/device/ascend/device_test.go`:
- Around line 1214-1231: Add regression coverage in the device request test
cases around the existing resourcememoryname scenario: add a Limits-only case
with an over-capacity memory request, and add a Requests case whose memory value
exceeds math.MaxInt32 and expects Memreq to equal math.MaxInt32. Import or
reference math.MaxInt32 consistently with the test package’s conventions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b451805e-a267-4996-8479-44857cb24f52

📥 Commits

Reviewing files that changed from the base of the PR and between 153defc and 6f2ee0e.

📒 Files selected for processing (2)
  • pkg/device/ascend/device.go
  • pkg/device/ascend/device_test.go

// request. Carry the requested value through so Fit
// rejects it, rather than letting the zero fall
// through to the whole-card default below.
m = min(memnums, math.MaxInt32)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no test covers this maxint32 clamp path. can u add a case with a request above int32 max?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Covered in 9432a48. The case requests 2147483648 and expects Memreq to equal math.MaxInt32.

The first regression case used 65536, which fits in int32 and so never
reached the clamp. Add a request above int32 max that expects MaxInt32,
and a limits-only case so both resource shapes are covered.

Signed-off-by: Neal006 <nealdaftary0405@gmail.com>
@hami-robot hami-robot Bot added size/M and removed size/S labels Aug 10, 2026
@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Flag Coverage Δ
unittests 62.18% <100.00%> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
pkg/device/ascend/device.go 84.82% <100.00%> (+0.07%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mesutoezdil mesutoezdil left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left two small questions inline. checked the fix against fit and trimMemory, logic looks correct.

@@ -339,6 +340,13 @@ func (dev *Devices) GenerateResourceRequests(ctr *corev1.Container) device.Conta
memnum = int(memnums)
} else {
m, _ := dev.trimMemory(memnums)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this only fixes the scheduler side. pod still passes admission, then fails later at fit. is that fine, or should mutateadmission also fall back to requests, like #2532 asks?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is deliberate. Failing at Fit is the correct outcome either way, since the pod cannot run on any card. What this PR removes is the silent success, where the pod scheduled and was accounted as 100% of a card.

MutateAdmission reading requests as well is the other half of #2532, but it changes behaviour for every requests-only Ascend pod, not just the over-capacity ones. That is a wider blast radius than this fix and it deserves its own review. I would rather keep this PR to the scheduler path and send the admission change separately.

Happy to fold it in here instead if a maintainer prefers one PR.

// request. Carry the requested value through so Fit
// rejects it, rather than letting the zero fall
// through to the whole-card default below.
m = min(memnums, math.MaxInt32)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test does not set memoryfactor above 1. does the clamp still force a reject after the factor scaling runs?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, added a case in cc01a6f.

The factor is applied at line 324, before trimMemory runs, so trimMemory and the clamp both see the already scaled value. A larger factor pushes the request further over capacity, never under it, so the reject holds.

The new case in Test_GenerateResourceRequestsFactor uses factor 1000 against the shared 128 MiB request. That scales to 128000, which exceeds the 32768 MemoryCapacity, and the test asserts Memreq stays 128000 with MemPercentagereq 0. Before this fix that same input produced Memreq 0 and MemPercentagereq 100, which Fit reads as the whole card.

memoryFactor scaling runs before trimMemory, so the clamp sees the already
scaled value. Add a case where the factor is what pushes the request past
MemoryCapacity, to pin that the scaled value is carried through instead of
falling back to the whole-card default.

Signed-off-by: Neal006 <nealdaftary0405@gmail.com>
@hami-robot hami-robot Bot added size/L and removed size/M labels Aug 11, 2026
@Neal006
Neal006 requested a review from mesutoezdil August 11, 2026 22:24
@mesutoezdil

Copy link
Copy Markdown
Contributor

This is being closed because it does not comply with the contribution guidelines.

@Neal006
Neal006 deleted the fix/ascend-over-capacity-memory branch August 13, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Ascend] Requests-only pods skip memory validation, so an over-capacity request becomes a whole-card request

3 participants