Skip to content

Commit

Permalink
Trim CRD to keep it compatible with kubectl apply
Browse files Browse the repository at this point in the history
Signed-off-by: Mikkel Oscar Lyderik Larsen <[email protected]>
  • Loading branch information
mikkeloscar committed Apr 15, 2024
1 parent 283ff61 commit b99cd97
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 34 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ $(GENERATED): go.mod $(CRD_TYPE_SOURCE)
./hack/update-codegen.sh

$(GENERATED_CRDS): $(GENERATED) $(CRD_SOURCES)
go run sigs.k8s.io/controller-tools/cmd/controller-gen crd:crdVersions=v1 paths=./pkg/apis/... output:crd:dir=docs || /bin/true || true
go run sigs.k8s.io/controller-tools/cmd/controller-gen crd:crdVersions=v1 paths=./pkg/apis/... output:crd:dir=docs
go run hack/crd/trim.go < docs/zalando.org_elasticsearchdatasets.yaml > docs/zalando.org_elasticsearchdatasets_trimmed.yaml
go run hack/crd/trim.go < docs/zalando.org_elasticsearchmetricsets.yaml > docs/zalando.org_elasticsearchmetricsets_trimmed.yaml
mv docs/zalando.org_elasticsearchdatasets_trimmed.yaml docs/zalando.org_elasticsearchdatasets.yaml
mv docs/zalando.org_elasticsearchmetricsets_trimmed.yaml docs/zalando.org_elasticsearchmetricsets.yaml

build.local: build/$(BINARY) $(GENERATED_CRDS)
build.linux: build/linux/$(BINARY)
Expand Down
31 changes: 0 additions & 31 deletions docs/zalando.org_elasticsearchdatasets.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
Expand Down Expand Up @@ -493,14 +492,6 @@ spec:
In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array
of string values. If the operator
is In or NotIn, the values array
must be non-empty. If the operator
is Exists or DoesNotExist, the
values array must be empty.
This array is replaced during
a strategic merge patch.
items:
type: string
type: array
Expand Down Expand Up @@ -6653,14 +6644,6 @@ spec:
In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array
of string values. If the operator
is In or NotIn, the values array
must be non-empty. If the operator
is Exists or DoesNotExist, the
values array must be empty.
This array is replaced during
a strategic merge patch.
items:
type: string
type: array
Expand Down Expand Up @@ -7175,14 +7158,8 @@ spec:
supported.'
properties:
apiVersion:
description: Version of the
schema the FieldPath is written
in terms of, defaults to "v1".
type: string
fieldPath:
description: Path of the field
to select in the specified
API version.
type: string
required:
- fieldPath
Expand Down Expand Up @@ -7223,22 +7200,14 @@ spec:
supported.'
properties:
containerName:
description: 'Container name:
required for volumes, optional
for env vars'
type: string
divisor:
anyOf:
- type: integer
- type: string
description: Specifies the output
format of the exposed resources,
defaults to "1"
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
description: 'Required: resource
to select'
type: string
required:
- resource
Expand Down
1 change: 0 additions & 1 deletion docs/zalando.org_elasticsearchmetricsets.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ require (
k8s.io/code-generator v0.28.8
k8s.io/metrics v0.28.8
sigs.k8s.io/controller-tools v0.13.0
sigs.k8s.io/yaml v1.3.0
)

require (
Expand Down Expand Up @@ -74,7 +75,6 @@ require (
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

replace k8s.io/klog => github.com/mikkeloscar/knolog v0.0.0-20190326191552-80742771eb6b
Expand Down
106 changes: 106 additions & 0 deletions hack/crd/trim.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// This program removes descriptions from the input CRD yaml to reduce its size.
//
// # Why
//
// When CRD is applied via `kubectl apply -f docs/stackset_crd.yaml` (aka client-side apply) kubectl stores
// CRD content into the kubectl.kubernetes.io/last-applied-configuration annotation which has
// size limit of 262144 bytes.
// If the size of the annotation exceeds the limit, kubectl will fail with the following error:
//
// The CustomResourceDefinition "stacksets.zalando.org" is invalid: metadata.annotations: Too long: must have at most 262144 bytes
//
// See https://github.com/kubernetes/kubectl/issues/712
//
// The CRD contains a lot of descriptions for k8s.io types and controller-gen
// does not allow to skip descriptions per field or per package,
// see https://github.com/kubernetes-sigs/controller-tools/issues/441
//
// # How
//
// It removes descriptions starting at the deepest level of the yaml tree
// until the size of the yaml converted to json is less than the maximum allowed annotation size.
package main

import (
"encoding/json"
"io"
"log"
"os"
"sort"

"sigs.k8s.io/yaml"
)

const maxAnnotationSize = 262144

func must(err error) {
if err != nil {
log.Fatal(err)
}
}

func mustGet[T any](v T, err error) T {
must(err)
return v
}

type description struct {
depth int
property map[string]any
value string
}

func main() {
yamlBytes := mustGet(io.ReadAll(os.Stdin))

o := make(map[string]any)
must(yaml.Unmarshal(yamlBytes, &o))

jsonBytes := mustGet(json.Marshal(o))
size := len(jsonBytes)

descriptions := collect(o, 0)

sort.Slice(descriptions, func(i, j int) bool {
if descriptions[i].depth == descriptions[j].depth {
return len(descriptions[i].value) > len(descriptions[j].value)
}
return descriptions[i].depth > descriptions[j].depth
})

for _, d := range descriptions {
if size <= maxAnnotationSize {
break
}
size -= len(d.value)
delete(d.property, "description")
}

if size > maxAnnotationSize {
log.Fatalf("YAML converted to JSON must be at most %d bytes long but it is %d bytes", maxAnnotationSize, size)
}

outYaml := mustGet(yaml.Marshal(o))
mustGet(os.Stdout.Write(outYaml))
}

func collect(o any, depth int) (descriptions []description) {
switch o := o.(type) {
case map[string]any:
for key, value := range o {
switch value := value.(type) {
case string:
if key == "description" {
descriptions = append(descriptions, description{depth, o, value})
}
default:
descriptions = append(descriptions, collect(value, depth+1)...)
}
}
case []any:
for _, item := range o {
descriptions = append(descriptions, collect(item, depth+1)...)
}
}
return descriptions
}

0 comments on commit b99cd97

Please sign in to comment.