Skip to content

Commit 4fd200c

Browse files
committed
apiextension: prune default values in storage
1 parent 135902b commit 4fd200c

File tree

6 files changed

+397
-10
lines changed

6 files changed

+397
-10
lines changed

staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -614,11 +614,24 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
614614
if val == nil {
615615
continue
616616
}
617-
structuralSchemas[v.Name], err = structuralschema.NewStructural(val.OpenAPIV3Schema)
617+
s, err := structuralschema.NewStructural(val.OpenAPIV3Schema)
618618
if *crd.Spec.PreserveUnknownFields == false && err != nil {
619-
utilruntime.HandleError(err)
619+
// This should never happen. If it does, it is a programming error.
620+
utilruntime.HandleError(fmt.Errorf("failed to convert schema to structural: %v", err))
620621
return nil, fmt.Errorf("the server could not properly serve the CR schema") // validation should avoid this
621622
}
623+
624+
if *crd.Spec.PreserveUnknownFields == false {
625+
// we don't own s completely, e.g. defaults are not deep-copied. So better make a copy here.
626+
s = s.DeepCopy()
627+
628+
if err := structuraldefaulting.PruneDefaults(s); err != nil {
629+
// This should never happen. If it does, it is a programming error.
630+
utilruntime.HandleError(fmt.Errorf("failed to prune defaults: %v", err))
631+
return nil, fmt.Errorf("the server could not properly serve the CR schema") // validation should avoid this
632+
}
633+
}
634+
structuralSchemas[v.Name] = s
622635
}
623636

624637
for _, v := range crd.Spec.Versions {

staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go_library(
44
name = "go_default_library",
55
srcs = [
66
"algorithm.go",
7+
"prune.go",
78
"surroundingobject.go",
89
"validation.go",
910
],
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package defaulting
18+
19+
import (
20+
"fmt"
21+
"reflect"
22+
23+
structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
24+
structuralobjectmeta "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/objectmeta"
25+
"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/pruning"
26+
"k8s.io/apimachinery/pkg/runtime"
27+
)
28+
29+
// PruneDefaults prunes default values according to the schema and according to
30+
// the ObjectMeta definition of the running server. It mutates the passed schema.
31+
func PruneDefaults(s *structuralschema.Structural) error {
32+
p := pruner{s}
33+
_, err := p.pruneDefaults(s, NewRootObjectFunc())
34+
return err
35+
}
36+
37+
type pruner struct {
38+
rootSchema *structuralschema.Structural
39+
}
40+
41+
func (p *pruner) pruneDefaults(s *structuralschema.Structural, f SurroundingObjectFunc) (changed bool, err error) {
42+
if s == nil {
43+
return false, nil
44+
}
45+
46+
if s.Default.Object != nil {
47+
orig := runtime.DeepCopyJSONValue(s.Default.Object)
48+
49+
obj, acc, err := f(s.Default.Object)
50+
if err != nil {
51+
return false, fmt.Errorf("failed to prune default value: %v", err)
52+
}
53+
if err := structuralobjectmeta.Coerce(nil, obj, p.rootSchema, true, true); err != nil {
54+
return false, fmt.Errorf("failed to prune default value: %v", err)
55+
}
56+
pruning.Prune(obj, p.rootSchema, true)
57+
s.Default.Object, _, err = acc(obj)
58+
if err != nil {
59+
return false, fmt.Errorf("failed to prune default value: %v", err)
60+
}
61+
62+
changed = changed || !reflect.DeepEqual(orig, s.Default.Object)
63+
}
64+
65+
if s.AdditionalProperties != nil && s.AdditionalProperties.Structural != nil {
66+
c, err := p.pruneDefaults(s.AdditionalProperties.Structural, f.Child("*"))
67+
if err != nil {
68+
return false, err
69+
}
70+
changed = changed || c
71+
}
72+
if s.Items != nil {
73+
c, err := p.pruneDefaults(s.Items, f.Index())
74+
if err != nil {
75+
return false, err
76+
}
77+
changed = changed || c
78+
}
79+
for k, subSchema := range s.Properties {
80+
c, err := p.pruneDefaults(&subSchema, f.Child(k))
81+
if err != nil {
82+
return false, err
83+
}
84+
if c {
85+
s.Properties[k] = subSchema
86+
changed = true
87+
}
88+
}
89+
90+
return changed, nil
91+
}

staging/src/k8s.io/apiextensions-apiserver/test/integration/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ go_test(
3636
"//staging/src/k8s.io/apiextensions-apiserver/pkg/cmd/server/options:go_default_library",
3737
"//staging/src/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
3838
"//staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures:go_default_library",
39+
"//staging/src/k8s.io/apiextensions-apiserver/test/integration/storage:go_default_library",
3940
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
4041
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
4142
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",

0 commit comments

Comments
 (0)