Skip to content

cue/cmd: import crd for importing Kubernetes CustomResourceDefinitions #2691

@justenstall

Description

@justenstall

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:

  1. 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
  2. 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).
  3. 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).
  4. 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:

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.

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions