Skip to content

Enable custom project-level resource quotas #16550

Merged
rak-phillip merged 15 commits intorancher:masterfrom
rak-phillip:task/14797-quotas
Feb 5, 2026
Merged

Enable custom project-level resource quotas #16550
rak-phillip merged 15 commits intorancher:masterfrom
rak-phillip:task/14797-quotas

Conversation

@rak-phillip
Copy link
Copy Markdown
Member

@rak-phillip rak-phillip commented Feb 2, 2026

Summary

This updates the Project Resource Quotas tab so that custom resource quotas can now be specified.

Fixes #14797

Occurred changes and/or fixed issues

  • Add custom type to resource quotas
  • Load and modify custom resource quotas
  • Test for extended with computed props and consts
  • Fix failing unit tests
  • Add unit tests for custom types

Technical notes summary

The following changes were made to enable custom quotas:

  • Add a new item, Custom, to the Resource Type dropdown. This options can be selected multiple times
  • Add a new Resource Identifier input that becomes enabled when the Resource Type is "custom"; this allows the user to specify a custom quota

The relationship between the Project and ProjectRow components gets a little complicated with the custom quotas. The components are designed in such a way that "Resource Type" is expected to be unique, but this is no longer the case with multiple "Custom" quotas. I'll call out some code snippets to highlight where special consideration needs to be made.

Areas or cases that should be tested

Project resource quotas should behave as they did before, in addition to being able to add new custom quotas.

Areas which could experience regressions

Existing resource quotas should still behave the same with these changes in place.

Screenshot/Video

image image

Checklist

  • The PR is linked to an issue and the linked issue has a Milestone, or no issue is needed
  • The PR has a Milestone
  • The PR template has been filled out
  • The PR has been self reviewed
  • The PR has a reviewer assigned
  • The PR has automated tests or clear instructions for manual tests and the linked issue has appropriate QA labels, or tests are not needed
  • The PR has reviewed with UX and tested in light and dark mode, or there are no UX changes
  • The PR has been reviewed in terms of Accessibility
  • The PR has considered, and if applicable tested with, the three Global Roles Admin, Standard User and User Base

Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
This updates existing tests so that a new wrapper is initialized for each test. I encountered issues with tests mutating the wrapper. This update is a more idiomatic style for testing Vue components.

Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
@rancher-ui-project-bot rancher-ui-project-bot bot added this to the v2.15.0 milestone Feb 2, 2026
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
@rak-phillip rak-phillip modified the milestones: v2.15.0, v2.14.0 Feb 2, 2026
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Comment on lines +44 to +53
const limit = this.value.spec.resourceQuota.limit;
const extendedKeys = Object.keys(limit.extended || {});

this.typeValues = Object.keys(limit).flatMap((k) => {
if (k !== TYPES.EXTENDED) {
return k;
}

return extendedKeys.map((ek) => `extended.${ ek }`);
});
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

typeValues was originally an array of selected values:

[
  "configMaps",
  "extended",
  "limitsCpu"
]

This pattern needed to be modified to work with multiple extended values, so we now produce an array that appends the custom types to extended:

[
  "configMaps",
  "extended.test1",
  "extended.test2",
  "extended.test3",
  "limitsCpu"
]

:mode="mode"
:types="remainingTypes(typeValues[props.i])"
:type="typeValues[props.i]"
:index="props.i"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It was just easier for me to think about the indexing by passing a prop and emitting the event along with the index.

Comment on lines +45 to +49
created() {
if (this.type.startsWith(TYPES.EXTENDED)) {
this.customType = this.type.split('.')[1];
} else {
this.customType = this.type;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is a side-effect of the updated typeValues pattern[^1]. Custom types will be strings formatted as extended.{ customType }..

edit: thinking about this more, this pattern needs some updating. This will break down with types like requests.nvidia.com/gpu.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Resolved with 9f20594

Comment on lines +2 to +3
EXTENDED: 'extended',
CONFIG_MAPS: 'configMaps',
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I originally had a string constant for EXTENDED, but added CONFIG_MAPS to fix failing unit tests that were relying on specific order in the RANCHER_TYPES array. After I decided to migrate the rest after I added these.

Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
@rak-phillip
Copy link
Copy Markdown
Member Author

The remove behavior is inaccurate.. this stems from the design of the ArrayList component and its usage array indexes as v-for keys #14742. I'm working on an alternative approach that will work for quotas.

codyrancher
codyrancher previously approved these changes Feb 3, 2026
Copy link
Copy Markdown
Member

@codyrancher codyrancher left a comment

Choose a reason for hiding this comment

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

The only reservation that I really had was the split between resource type and resourceIdentifier.

In my mind I think the UX I would've preferred would be just have a Resource Identifier with a taggable labeled select where the user could type in the custom identifier if needed.

Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
Adding a key to the ResourceQuota component will force it to re-render when the key is incremented. This resolves issues with the ArrayList component rendering incorrect rows because it uses an index as key in its v-for.

This approach can incur a performance penalty, but I expect the number of rows to remain reasonably small; the added reliability of this approach is more important.

Signed-off-by: Phillip Rak <rak.phillip@gmail.com>
@codyrancher codyrancher self-requested a review February 4, 2026 23:19
@rak-phillip rak-phillip merged commit ae9cd3b into rancher:master Feb 5, 2026
90 of 96 checks passed
@rak-phillip rak-phillip deleted the task/14797-quotas branch February 5, 2026 01:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Projects: Add storage class based resource quotas

2 participants