Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ create apis/v1alpha2, add new ResourceSchemas #3318

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

xrstf
Copy link
Contributor

@xrstf xrstf commented Mar 3, 2025

Summary

This PR adds a new version to the apis.kcp.io API, v1alpha2. This new version only contains the slightly updated APIExports, which now support a more elaborate configuration structure to enable virtual resources in the future.

All the code was updated to refer to v1alpha2.APIExports.

Conversion between the two versions is handled by a wrapper around the stock CR Converter, see individual commits for more information.

Related issue(s)

Fixes #3301

TODO:

  • Add admission to check valid json annotations
  • Add admission to check for duplicates

Confirmed that if you add a new type into a new API and don't sort converters, all stuff just explodes in tests and generation :) which is good!

Release Notes

Introduce `apis.kcp.io/v1alpha2`, containing solely `APIExport`

@kcp-ci-bot kcp-ci-bot added release-note-none Denotes a PR that doesn't merit a release note. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. dco-signoff: yes Indicates the PR's author has signed the DCO. labels Mar 3, 2025
@kcp-ci-bot
Copy link
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@kcp-ci-bot kcp-ci-bot added the kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API label Mar 3, 2025
@kcp-ci-bot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

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

@kcp-ci-bot kcp-ci-bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Mar 3, 2025
@xrstf
Copy link
Contributor Author

xrstf commented Mar 3, 2025

/test all

Copy link
Contributor

@mjudeikis mjudeikis left a comment

Choose a reason for hiding this comment

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

I think few things are missing here:

  1. Conversion webhook for v1alpha1 to v1alpha2
  2. I would really like it to be split in commits:
    All API changes and webhook into 1 commit
    Sed replace changes to another.

But Im in the same boat as you for the approach. @sttts - we need your guidance here :)

@xrstf
Copy link
Contributor Author

xrstf commented Mar 3, 2025

I would really like it to be split in commits: All API changes and webhook into 1 commit, Sed replace changes to another.

Will do, for rebasing it was just simpler to keep it locally as 1 commit for now.

@xrstf xrstf force-pushed the resourceschemas branch 3 times, most recently from 05c99d7 to ba86ec7 Compare March 7, 2025 10:04
@xrstf
Copy link
Contributor Author

xrstf commented Mar 7, 2025

/test all

@kcp-ci-bot kcp-ci-bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 10, 2025
@xrstf xrstf force-pushed the resourceschemas branch from ba86ec7 to be360df Compare March 10, 2025 19:41
@kcp-ci-bot kcp-ci-bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 10, 2025
@xrstf
Copy link
Contributor Author

xrstf commented Mar 10, 2025

/test all

@xrstf xrstf force-pushed the resourceschemas branch 2 times, most recently from bbc80c8 to b6aabe3 Compare March 11, 2025 15:59
@xrstf
Copy link
Contributor Author

xrstf commented Mar 11, 2025

/test all

@xrstf xrstf force-pushed the resourceschemas branch from b6aabe3 to c36184f Compare March 11, 2025 19:00
@kcp-ci-bot kcp-ci-bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. and removed release-note-none Denotes a PR that doesn't merit a release note. labels Mar 11, 2025
@xrstf
Copy link
Contributor Author

xrstf commented Mar 11, 2025

/test all

Schema: "foo",
Storage: ResourceSchemaStorage{
CRD: &ResourceSchemaStorageCRD{},
},
Copy link
Member

Choose a reason for hiding this comment

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

I don't see valid ResourceSchemas. This would be tested with fuzzing.

},
},
}},
},
Copy link
Member

Choose a reason for hiding this comment

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

how do we know that everything in the spec is copied over to v1alpha1 and back? This would be tested with fuzzing. We must have these tests. Somebody adds a field and forgets the conversion. Then we have dataloss 😞

}

func Convert_v1alpha1_APIExportSpec_To_v1alpha2_APIExportSpec(in *apisv1alpha1.APIExportSpec, out *APIExportSpec, s kubeconversion.Scope) error {
if in.Identity != nil {
Copy link
Member

Choose a reason for hiding this comment

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

this is untested

}
}

if in.MaximalPermissionPolicy != nil {
Copy link
Member

Choose a reason for hiding this comment

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

this is untested

}
}

if claims := in.PermissionClaims; claims != nil {
Copy link
Member

Choose a reason for hiding this comment

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

this is untested

Copy link
Contributor

Choose a reason for hiding this comment

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

By untested, you mean if it's being converted roundtrip?

if overhanging, ok := in.Annotations[resourceSchemasAnnotation]; ok {
resourceSchemas := []ResourceSchema{}
if err := json.Unmarshal([]byte(overhanging), &resourceSchemas); err != nil {
return fmt.Errorf("failed to decode schemas from JSON: %w", err)
Copy link
Member

Choose a reason for hiding this comment

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

do we have admission that checks this not to happen?

out.Spec.ResourceSchemas = []ResourceSchema{}
}

out.Spec.ResourceSchemas = append(out.Spec.ResourceSchemas, resourceSchemas...)
Copy link
Member

@sttts sttts Mar 20, 2025

Choose a reason for hiding this comment

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

this can lead to duplicates without admission checking that there is no duplicate.

out.Spec.ResourceSchemas = append(out.Spec.ResourceSchemas, resourceSchemas...)
}

delete(out.Annotations, resourceSchemasAnnotation)
Copy link
Member

Choose a reason for hiding this comment

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

All these mutations look suspicious. Wondering whether we might cache mutations here.

Look at the invariant defined here:

	// Convert attempts to convert one object into another, or returns an error. This
	// method does not mutate the in object, but the in and out object might share data structures,
	// i.e. the out object cannot be mutated without mutating the in object as well.
	// The context argument will be passed to all nested conversions.
	Convert(in, out, context interface{}) error

In other words, in and out share data structure. But when you mutate out, you must do a (hopefully shallow, avoid deep copies) copy.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is fuzzing test where we check that we didn't modified the input itself, right? Or you had something else inmind with cache ?

@kcp-ci-bot kcp-ci-bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 27, 2025
xrstf and others added 15 commits March 27, 2025 21:10
The conversion ensures that virtual ResourceSchemas are retained in v1alpha1 by using an annotion.
I made the assumption that the order of resource schemas is not important, as during a roundtrip
conversion, non-cRD resource schemas would always be added *after* CRD resource schemas.

On-behalf-of: @SAP [email protected]
The original plan was to use a regular, actual conversion webhook server to
handle converting between v1alpha1 and v1alpha2. This was to be hosted in the
same kcp shard process and server handler (i.e. as part of the
preHandlerChainMux).

However this presented a long list of problems:

* If the webhook was part of the main kcp process, it would share the serving
  certificate. Since the CABundle has to be included in the CRDs, this means
  that kcp would need to know the CA that signed its serving cert, which can
  be troublesome to automate (cert-manager ACME issuers do not provide the CA)
  and to configure (requiring an additional CLI flag).
* If the webhook would use its own certificate (by making use of SNI), it would
  need its own dedicated hostname that resolves to localhost. But since the
  admin is technically free to run kcp with `--external-hostname=localhost`,
  choosing a good name is difficult (localhost or 127.0.0.1).

  One could try to inject a custom HTTP client that has a custom RoundTripper
  that understands a special "kcp.local" domain, but this requires copying
  hundreds of lines of upstream k/k code because ultimately the client is
  constructed in deeply nested structs.
* Additionally, if the webhook were to create its own certificate and CA, it
  would be different on each shard. And since the CABundle is par of the
  system CRDs on each shard's etcd, it would not be possible to actually
  re-generatet the CA on each startup, it would need to be persisted.

  But persistence is annoying, especially in Kubernetes. Having a volume for
  just a single certificate is overkill.

  Another solution for this could have been to persist the certificate in etcd.
  But at this point we abandoned this idea entirely.

Instead, this commit adds a simple wrapper around k/k's CRConverter. The wrapper
detects the apis.kcp.io API group and simply calls the conversion functions
directly, skipping the entire webhook logic. This is faster, more efficient,
requires no extra configuration and is simple to understand.

On-behalf-of: @SAP [email protected]
This is mostly adding a bunch of imports and here and there converting between PermissionClaims,
as we still have those for APIBindings in v1alpha1.

On-behalf-of: @SAP [email protected]
same, but less interesting than the previous commit

On-behalf-of: @SAP [email protected]
This was not properly done in kcp-dev#3336.

On-behalf-of: @SAP [email protected]
On-behalf-of: @SAP [email protected]
Signed-off-by: Mangirdas Judeikis <[email protected]>
@kcp-ci-bot kcp-ci-bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 27, 2025
@mjudeikis
Copy link
Contributor

/retest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dco-signoff: yes Indicates the PR's author has signed the DCO. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feature: Implement API change for APIExport latestResourceSchemas
4 participants