-
Notifications
You must be signed in to change notification settings - Fork 394
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
✨ Add OpenAPI v3 schema support to the Virtual Workspace framework #3246
base: main
Are you sure you want to change the base?
Conversation
Skipping CI for Draft Pull Request. |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: 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 |
4003968
to
4d4d225
Compare
Signed-off-by: Nabarun Pal <pal.nabarun95@gmail.com>
Signed-off-by: Marko Mudrinić <mudrinic.mare@gmail.com> On-behalf-of: @SAP marko.mudrinic@sap.com
4d4d225
to
5e160a7
Compare
Signed-off-by: Marko Mudrinić <mudrinic.mare@gmail.com> On-behalf-of: @SAP marko.mudrinic@sap.com
/retest e2e-sharded flake real? |
@sttts I believe it's a flake, it's now green and I didn't touch anything related to that (I think). I'm now working on adding an E2E test for this feature too and it appears to be pretty stable (I still didn't push it, will likely do it tomorrow). |
log = log.WithValues("key", key) | ||
entry, ok := o.services.Get(key) | ||
if !ok { | ||
log.V(7).Info("Generating OpenAPI v3 specs") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a heavy operation, isn't it? Shouldn't we lock the saved key somehow and let other parties with the same interest wait? This even applies to one client collecting specs for example.
A common pattern for that: store an item struct in the lru cache with a wait channel:
type item struct {
done <-chan struct{}
err error
service http.Handler
}
Every cache hit will wait for done
before accessing err
or service
. The go routine owning this will add it to the lru cache before starting the heavy work. It will set err
or service
and then close done
to wake all other waiters up.
This needs an e2e test. |
|
||
const ( | ||
// DefaultServiceCacheSize is the default size of the OpenAPI service cache. | ||
DefaultServiceCacheSize = 50 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also have a ttl cache 🤔
@@ -177,14 +180,21 @@ func (c completedConfig) New(virtualWorkspaceName string, delegationTarget gener | |||
|
|||
s.GenericAPIServer.Handler.GoRestfulContainer.Add(discovery.NewLegacyRootAPIHandler(c.GenericConfig.DiscoveryAddresses, s.GenericAPIServer.Serializer, "/api").WebService()) | |||
|
|||
if !c.GenericConfig.SkipOpenAPIInstallation { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for my understanding here to match it with the PR description: Your intention was that developers of virtual workspaces that use the virtual
framework can disable OpenAPI, not that kcp admins can disable OpenAPI on their default kcp VWs, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To put it the other way around, what do we actually want and/or need more? My understanding of this implementation is that it's more towards those who run virtual workspaces, i.e. kcp-admins. Do we want both options?
Summary
This PR continues work done in #3059. Huge thanks to @palnabarun for all the work on this feature so far!
This PR adds OpenAPI v3 schema support to the Virtual Workspace dynamic framework.
A new
openAPIHandler
has been implemented that utilizes thekube-openapi
library to generate and serve the OpenAPI v3 specs. The specs are generated for the following routes:/api
and/apis
- information about API groups/apis/<group>
- information about API versions/api/v1
and/apis/<group>/<version>
- specs for the concrete GroupVersionExample calls:
Specs are generated for all
APIDefintions
available in that virtual workspace. In other words, everything that's served byGetAPIDefinitionSet
function is available in the OpenAPI v3 spec in that virtual workspace.The implementation is a bit different to what the regular API servers are doing due to the way how are virtual workspaces implemented. The regular API servers are building the OpenAPI v3 specs from web services registered in that API server. However, this is not an option for the virtual workspaces API server because it only has three web services registered:
/api
,/apis
, and/version
. None of these three web services have any subroute registered, so there's no information about e.g./apis/<group>
or/apis/<group>/<version>
. That makes generating the OpenAPI v3 specs using the "usual approach" impossible.I mitigated that by:
/api
,/apis/
, and/version
from the respective web services/apis/<group>
, and then generate the OpenAPI v3 specs for these web servicesAPIDefinitions
toCustomResourceDefintions
, and then using the appropriate function from thekube-openapi
library to generate the specsAt the end, all these specs are merged into one and served. This is heavily inspired by #3246
This is also a bit different than idea in #3059, as #3059 tried to manually implement each OpenAPI v3 route, while this heavily relies on the
kube-openapi
library.To make this more performant, a simple caching solution has been implemented. I'm generating a hash out of the APIDefinition's spec, and then use it to generate a key. That key is used for the LRU cache where I store the OpenAPI v3 service. This is almost copy-paste of implementation from #3246.
As requested by the community, I implemented a simple way to disable the OpenAPI v3 generation by setting the
SkipOpenAPIInstallation
extra configuration option totrue
.Finally, unlike the original implementation in #3059, this implementation doesn't tap into the
CreateServingInfoFor
function. Thinking about that, I think it would have been possible and it could have enabled more effective caching, but because of the complexity, I decided to go with a "simpler" initial implementation, and we can consider doing this in the future.The only missing part are E2E tests. This is something that I plan on adding later, potentially as a follow up PR if that's okay.
Related issue(s)
Fixes #3242
Release Notes