Skip to content

Drop the scale subresource before building OpenAPI for schema generation#119

Merged
negz merged 1 commit into
crossplane:mainfrom
negz:scale-of-justice
Jun 15, 2026
Merged

Drop the scale subresource before building OpenAPI for schema generation#119
negz merged 1 commit into
crossplane:mainfrom
negz:scale-of-justice

Conversation

@negz

@negz negz commented Jun 15, 2026

Copy link
Copy Markdown
Member

Fixes #117

When an XRD or CRD declares a scale subresource, crossplane xrd generate produces language schemas for the autoscaling/v1 Scale type in place of the resource's own model. For Python the generated module's imports also change shape, so importing the model fails outright with ModuleNotFoundError: No module named 'models.ai.apimachinery'.

ToOpenAPI builds the intermediate OpenAPI document with BuildOpenAPIV3, which models the resource's whole REST surface, not just its structural schema. Declaring a scale subresource adds a /scale endpoint whose request and response body is an autoscaling/v1 Scale, so the builder adds Scale, ScaleSpec, and ScaleStatus to the document's components. The meta types it always emits (ObjectMeta and friends) get redirected to a shared module by a later transform, but the autoscaling types don't, so the language generator models them into the resource's own module.

The scale subresource is a runtime API behaviour with no bearing on the generated model, so this clears it before the conversion. BuildOpenAPIV3 then never emits the /scale endpoint or its Scale schemas, and the resource's model generates as it did before.

I have:

  • Read and followed Crossplane's contribution process.
  • Run nix flake check to ensure this PR is ready for review.
  • Added or updated unit tests.
  • Linked a PR or a docs tracking issue to document this change.
  • Added backport release-x.y labels to auto-backport this PR.

@negz negz requested review from a team, jcogilvie and tampakrap as code owners June 15, 2026 22:31
@negz negz requested review from bobh66 and removed request for a team June 15, 2026 22:31
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@negz, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 49 minutes and 39 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f5b115be-39bf-4afa-a40d-fff69a982f99

📥 Commits

Reviewing files that changed from the base of the PR and between 510a9e0 and 809565b.

📒 Files selected for processing (2)
  • internal/crd/convert.go
  • internal/crd/convert_test.go
📝 Walkthrough

Walkthrough

modifyCRDManifestFields in convert.go now sets Subresources.Scale to nil before calling BuildOpenAPIV3, preventing autoscaling Scale-related schemas from being included in generated OpenAPI components. A new test TestToOpenAPIScaleSubresource verifies the resource schema is preserved and autoscaling schemas are absent.

Changes

Scale Subresource Exclusion Fix

Layer / File(s) Summary
Nil out scale subresource and verify schema output
internal/crd/convert.go, internal/crd/convert_test.go
modifyCRDManifestFields clears Subresources.Scale to nil when Subresources is non-nil, preventing BuildOpenAPIV3 from emitting Scale/ScaleSpec/ScaleStatus into components.schemas. TestToOpenAPIScaleSubresource unmarshals a minimal CRD with a scale block, calls ToOpenAPI, and asserts the resource schema is present while all three autoscaling schemas are absent.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: removing the scale subresource before OpenAPI generation to fix schema generation issues.
Description check ✅ Passed The description clearly explains the problem (scale subresource causing incorrect schema generation), root cause, and solution, with good context for reviewers.
Linked Issues check ✅ Passed The PR directly addresses issue #117 by removing the scale subresource before OpenAPI generation, preventing autoscaling schemas from displacing the resource's own model.
Out of Scope Changes check ✅ Passed All changes are focused on fixing the scale subresource issue: modifications to convert.go and corresponding unit test additions with no extraneous changes.
Breaking Changes ✅ Passed PR modifies only internal/crd/ files (not apis/** or cmd/**), so the breaking-change check does not apply. No public APIs were modified.
Feature Gate Requirement ✅ Passed This PR is a bug fix in internal/crd/, not a new experimental feature. It corrects incorrect schema generation when scale subresources are declared, without introducing new experimental features or...

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

@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)
internal/crd/convert_test.go (1)

115-185: ⚡ Quick win

Please align this test with the table-driven args/want pattern used in this repo.

Could we convert this single-case test into a table-driven case so follow-up scenarios (e.g., multiple versions, scale absent, malformed subresource blocks) can be added consistently without duplicating setup/assertion code?

As per coding guidelines, **/*_test.go should enforce a table-driven test structure with an args/want pattern.

🤖 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 `@internal/crd/convert_test.go` around lines 115 - 185, Convert the
TestToOpenAPIScaleSubresource function to use a table-driven test pattern with
args and want fields. Create a struct type to hold test case data including the
CRD YAML input (args) and expected validation results like the presence of
required schemas and absence of leaked autoscaling schemas (want). Replace the
single test body with a loop that iterates over a slice of test cases, executing
the same ToOpenAPI call and assertions for each case. This will allow future
test scenarios (multiple versions, missing scale subresource, malformed blocks)
to be added as additional table entries without duplicating the setup and
assertion logic.

Source: Coding guidelines

🤖 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 `@internal/crd/convert_test.go`:
- Around line 115-185: Convert the TestToOpenAPIScaleSubresource function to use
a table-driven test pattern with args and want fields. Create a struct type to
hold test case data including the CRD YAML input (args) and expected validation
results like the presence of required schemas and absence of leaked autoscaling
schemas (want). Replace the single test body with a loop that iterates over a
slice of test cases, executing the same ToOpenAPI call and assertions for each
case. This will allow future test scenarios (multiple versions, missing scale
subresource, malformed blocks) to be added as additional table entries without
duplicating the setup and assertion logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8e943d0b-4f47-4b8d-b102-a71323b3f84a

📥 Commits

Reviewing files that changed from the base of the PR and between 3df82fc and 510a9e0.

📒 Files selected for processing (2)
  • internal/crd/convert.go
  • internal/crd/convert_test.go

@negz negz force-pushed the scale-of-justice branch from 510a9e0 to 9a2592d Compare June 15, 2026 22:37
Crossplane v2.3 lets XRDs configure a scale subresource. When a resource
declares one, generating language schemas for it produces models of the
autoscaling/v1 Scale type in place of the resource's own model. For
Python the generated module's imports also change shape, so importing
the model fails outright with "No module named 'models.ai.apimachinery'".

ToOpenAPI builds the intermediate OpenAPI document with BuildOpenAPIV3,
which emits the resource's whole REST API surface, not just its
structural schema. Declaring a scale subresource adds a /scale endpoint
whose request and response body is an autoscaling/v1 Scale. To describe
that endpoint the builder adds the Scale, ScaleSpec, and ScaleStatus
schemas to the document's components. The meta types it always emits
(ObjectMeta and friends) are redirected to a shared module by a later
transform, but the autoscaling types are not, so the language generator
models them into the resource's own module.

The scale subresource is a runtime API behaviour, not part of the
resource's structural schema, so it has no bearing on the generated
model. This clears it before the conversion, so BuildOpenAPIV3 never
emits the /scale endpoint or its Scale schemas and the resource's model
generates as it did before.

Fixes crossplane#117.

Signed-off-by: Nic Cope <nicc@rk0n.org>
@negz negz force-pushed the scale-of-justice branch from 9a2592d to 809565b Compare June 15, 2026 22:41

@adamwg adamwg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. It seems like the scale subresource causes a problem only for Python (I believe due to how we structure the generated Python packages), but dropping scale before generating is reasonable.

I wonder if this would let us also simplify some of the generator code, since I know it has special handling for the v1/autoscaling Scale resource.

@negz negz merged commit 1a0f229 into crossplane:main Jun 15, 2026
10 checks passed
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.

crossplane xrd generate models the autoscaling Scale type instead of the resource when a scale subresource is declared

2 participants