-
Notifications
You must be signed in to change notification settings - Fork 327
Description
Is your feature request related to a problem? Please describe.
CUE cannot import Kubernetes CustomResourceDefinitions (CRDs). Importing CRDs into CUE would be a huge value add for Kubernetes users.
Describe the solution you'd like
I would like a cue import crd
command that is able to import a YAML or JSON encoded CustomResourceDefinition to CUE.
Describe alternatives you've considered
cue import openapi
Since CRDs use a variation of OpenAPIv3 to define their schema, cue import openapi
can be used to import the schema with some extra help from a query tool like yq. Here is an example script to extract a valid OpenAPI definition from the CRD with yq and then import it as CUE:
CRD="<file>.yaml"
yq '{"openapi": "3.0.0"} *
{"info": {"title": .spec.group}} *
{"info": {"version": .spec.versions[0].name}} *
{"components": { "schemas": { .spec.names.kind: .spec.versions[0].schema.openAPIV3Schema}}}' \
"$CRD_FILE" > crd-openapi.yaml
cue import openapi crd-openapi.yaml
This is not a viable solution because of Kubernetes' OpenAPIv3 extensions explained in the Additional Context section below.
cue get go
Many CRDs are created with a code generation tool such as controller-gen
(from the kubebuilder SDK), which generates the CRD from annotated Go code. I have used cue get go
to import the CRD from the Go types, but it is not a 100% match for the controller-gen
-created schema. Adding direct support for CRD --> CUE is ideal.
See also: #2679
Additional context
OpenAPIv3 vs Structural Schema
Kubernetes calls its flavor of OpenAPIv3 "structural schema", which is defined as follows:
A structural schema is an OpenAPI v3.0 validation schema which:
- specifies a non-empty type (via type in OpenAPI) for the root, for each specified field of an object node (via properties or additionalProperties in OpenAPI) and for each item in an array node (via items in OpenAPI), with the exception of:
- a node with x-kubernetes-int-or-string: true
- a node with x-kubernetes-preserve-unknown-fields: true
- for each field in an object and each item in an array which is specified within any of allOf, anyOf, oneOf or not, the schema also specifies the field/item outside of those logical junctors (compare example 1 and 2).
- does not set description, type, default, additionalProperties, nullable within an allOf, anyOf, oneOf or not, with the exception of the two pattern for x-kubernetes-int-or-string: true (see below).
- if metadata is specified, then only restrictions on metadata.name and metadata.generateName are allowed.
Source: Specifying a structural schema
CEL Validation
As seen in the snippet above, Kubernetes extends the OpenAPIv3 syntax with fields prefixed by x-kubernetes-
. The most challenging to incorporate will be the newer x-kubernetes-validations
field, used to define validations rules with the Common Expression Language (CEL). Translating CEL to CUE will be a big lift, but it is being cemented as the desired way for k8s developers to define validation rules in CRDs, k8s admission controller webhooks, and eventually even the native Kubernetes APIs. CEL validation will be incompatible with CUE in some cases, because it allows validating an updated Kubernetes object by comparing it to its existing values. Ideally, validation rules that have no CUE equivalent can be preserved so the CRD can round-trip CRD --> CUE --> CRD without losing information.
References:
- Kubernetes Docs: Common Expression Language in Kubernetes
- Kubernetes Docs: CustomResourceDefinition Validation rules
- YouTube: The Path to Self Contained CRDs - Cici Huang, Google
Possible existing implementation?
The file encoding/openapi/crd.go contains a seemingly unused implementation of CRD decoding. If anyone is familiar with this code and knows what state it is in, I would appreciate the help as a new contributor.