Skip to content

Conversation

nkvoll
Copy link

@nkvoll nkvoll commented Mar 6, 2025

This is just taking a quick stab at something for #2638, just to see what it would take to fix. I'm not experienced with nor do I fully understand the ast or if what I'm doing is very uncanonical (just learning cue and first time potential contributor), so please bear with me as I'm looking for some feedback on whether some direction like this makes sense or if I'm looking in the wrong directions.

What I wanted to add support for is extending the openapi schema to support extensions like CEL (see https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation-rules). This requires a little more than adding string string:string key:value pairs, so I opted for using JSON inside the cue attribute.

Having the attribute be @openapi(extension:keyName:json-value) meant a little more parsing than something like @openapiExtension(keyName:json-value) (or similar).

Example

Example resource (example.cue):

package example

#SomeResource: {
	spec: {
		parameters: {
			foo: string
        } @openapi(extension=x-kubernetes-validations:[
            {
                "rule": "self.minReplicas <= self.replicas && self.replicas <= self.maxReplicas",
                "message": "replicas should be in the range minReplicas..maxReplicas."
            }
        ])
    }
}

Generate:

go run ./cmd/cue def example.cue -o example.openapi.yaml --out openapi+yaml

Output

openapi: 3.0.0
info:
  title: Generated by cue.
  version: no version
paths: {}
components:
  schemas:
    SomeResource:
      type: object
      required:
        - spec
      properties:
        spec:
          type: object
          required:
            - parameters
          properties:
            parameters:
              type: object
              required:
                - foo
              properties:
                foo:
                  type: string
              x-kubernetes-validations:
                - rule: self.minReplicas <= self.replicas && self.replicas <= self.maxReplicas
                  message: replicas should be in the range minReplicas..maxReplicas.

@nkvoll nkvoll force-pushed the openapi-extensions branch from d657071 to 82a7575 Compare March 6, 2025 23:16
@myitcv
Copy link
Member

myitcv commented Mar 8, 2025

Thanks for this @nkvoll - I'll ask @rogpeppe to take a look and get back to you!

@rogpeppe
Copy link
Member

@nkvoll Thanks very much for the PR! We definitely want to support aspects of OpenAPI like this, although the right approach isn't entirely clear currently. For now, we are super busy in the run up to Kubecon. We will get back to you with feedback on this after that :)

@nkvoll
Copy link
Author

nkvoll commented May 23, 2025

Hi @rogpeppe, just checking in if you have had some time to take a look. I just pushed a change that moves the extension definition from being json to being in cue (not 100% sure on the implementation, whether there is a better / more canonical approach available -- happy to learn).

Example usage right now (pluralized extensions since multiple extensions can be defined here -- though there are currently no explicit guardrails for not colliding with the built-in attributes):

package example

#SomeResource: {
    spec: {
        parameters: {
            minReplicas: int
            maxReplicas: int
            replicas: int
        } @openapi(extensions={
            "x-kubernetes-validations": [
                {
                    rule: "self.minReplicas <= self.replicas && self.replicas <= self.maxReplicas",
                    message: "replicas should be in the range minReplicas..maxReplicas",
                }
            ]
        })
    }
}

@rogpeppe
Copy link
Member

I like the generality of this approach, but if the main objective is support for validation expressions, we should probably see whether it might be possible to express those in CUE directly rather than in an auxilliary non-CUE syntax in attributes.

To take the example from the validation rules page, ISTM it would be much nicer if it was possible to specify it as:

minReplicas!: int & <= replicas
replicas!: & <= maxReplicas
maxReplicas!: int

rather than using the Kubernetes extension syntax directly.

I've created #4048 to track that possibility.

Given that this particular PR implements general support for OpenAPI "extensions", it would be nice to know what other kinds of extension are also good use cases.

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.

3 participants