Skip to content

Commit 8456a51

Browse files
authored
Merge pull request kubernetes#95736 from Jefftree/reuse-parser
Reuse SSA type converter for resources in the same API Group
2 parents c5ecae7 + 1f986cc commit 8456a51

22 files changed

+120
-124
lines changed

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,14 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
669669
openAPIModels = nil
670670
}
671671

672+
var typeConverter fieldmanager.TypeConverter = fieldmanager.DeducedTypeConverter{}
673+
if openAPIModels != nil {
674+
typeConverter, err = fieldmanager.NewTypeConverter(openAPIModels, crd.Spec.PreserveUnknownFields)
675+
if err != nil {
676+
return nil, err
677+
}
678+
}
679+
672680
safeConverter, unsafeConverter, err := r.converterFactory.NewConverter(crd)
673681
if err != nil {
674682
return nil, err
@@ -842,13 +850,12 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
842850
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
843851
reqScope := *requestScopes[v.Name]
844852
reqScope.FieldManager, err = fieldmanager.NewDefaultCRDFieldManager(
845-
openAPIModels,
853+
typeConverter,
846854
reqScope.Convertor,
847855
reqScope.Defaulter,
848856
reqScope.Creater,
849857
reqScope.Kind,
850858
reqScope.HubGroupVersion,
851-
crd.Spec.PreserveUnknownFields,
852859
false,
853860
)
854861
if err != nil {
@@ -879,13 +886,12 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
879886
statusScope := *requestScopes[v.Name]
880887
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
881888
statusScope.FieldManager, err = fieldmanager.NewDefaultCRDFieldManager(
882-
openAPIModels,
889+
typeConverter,
883890
statusScope.Convertor,
884891
statusScope.Defaulter,
885892
statusScope.Creater,
886893
statusScope.Kind,
887894
statusScope.HubGroupVersion,
888-
crd.Spec.PreserveUnknownFields,
889895
true,
890896
)
891897
if err != nil {

staging/src/k8s.io/apiserver/pkg/endpoints/groupversion.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"k8s.io/apiserver/pkg/admission"
3131
"k8s.io/apiserver/pkg/authorization/authorizer"
3232
"k8s.io/apiserver/pkg/endpoints/discovery"
33+
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
3334
"k8s.io/apiserver/pkg/registry/rest"
3435
openapiproto "k8s.io/kube-openapi/pkg/util/proto"
3536
)
@@ -71,6 +72,7 @@ type APIGroupVersion struct {
7172
Defaulter runtime.ObjectDefaulter
7273
Linker runtime.SelfLinker
7374
UnsafeConvertor runtime.ObjectConvertor
75+
TypeConverter fieldmanager.TypeConverter
7476

7577
EquivalentResourceRegistry runtime.EquivalentResourceRegistry
7678

staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/BUILD

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ go_library(
1212
"skipnonapplied.go",
1313
"stripmeta.go",
1414
"structuredmerge.go",
15+
"typeconverter.go",
16+
"versionconverter.go",
1517
],
1618
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager",
1719
importpath = "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager",
@@ -29,6 +31,8 @@ go_library(
2931
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
3032
"//vendor/sigs.k8s.io/structured-merge-diff/v4/fieldpath:go_default_library",
3133
"//vendor/sigs.k8s.io/structured-merge-diff/v4/merge:go_default_library",
34+
"//vendor/sigs.k8s.io/structured-merge-diff/v4/typed:go_default_library",
35+
"//vendor/sigs.k8s.io/structured-merge-diff/v4/value:go_default_library",
3236
],
3337
)
3438

@@ -58,11 +62,14 @@ go_test(
5862
"lastappliedupdater_test.go",
5963
"managedfieldsupdater_test.go",
6064
"skipnonapplied_test.go",
65+
"typeconverter_test.go",
66+
"versionconverter_test.go",
6167
],
6268
data = [
6369
"endpoints.yaml",
6470
"node.yaml",
6571
"pod.yaml",
72+
"testdata/swagger.json",
6673
"//api/openapi-spec",
6774
],
6875
embed = [":go_default_library"],

staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/capmanagers_test.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package fieldmanager_test
17+
package fieldmanager
1818

1919
import (
2020
"bytes"
@@ -29,28 +29,27 @@ import (
2929
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3030
"k8s.io/apimachinery/pkg/runtime"
3131
"k8s.io/apimachinery/pkg/runtime/schema"
32-
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
3332
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
3433
)
3534

3635
type fakeManager struct{}
3736

38-
var _ fieldmanager.Manager = &fakeManager{}
37+
var _ Manager = &fakeManager{}
3938

40-
func (*fakeManager) Update(_, newObj runtime.Object, managed fieldmanager.Managed, _ string) (runtime.Object, fieldmanager.Managed, error) {
39+
func (*fakeManager) Update(_, newObj runtime.Object, managed Managed, _ string) (runtime.Object, Managed, error) {
4140
return newObj, managed, nil
4241
}
4342

44-
func (*fakeManager) Apply(_, _ runtime.Object, _ fieldmanager.Managed, _ string, _ bool) (runtime.Object, fieldmanager.Managed, error) {
43+
func (*fakeManager) Apply(_, _ runtime.Object, _ Managed, _ string, _ bool) (runtime.Object, Managed, error) {
4544
panic("not implemented")
4645
return nil, nil, nil
4746
}
4847

4948
func TestCapManagersManagerMergesEntries(t *testing.T) {
5049
f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod"),
5150
false,
52-
func(m fieldmanager.Manager) fieldmanager.Manager {
53-
return fieldmanager.NewCapManagersManager(m, 3)
51+
func(m Manager) Manager {
52+
return NewCapManagersManager(m, 3)
5453
})
5554

5655
podWithLabels := func(labels ...string) runtime.Object {
@@ -115,8 +114,8 @@ func TestCapManagersManagerMergesEntries(t *testing.T) {
115114
func TestCapUpdateManagers(t *testing.T) {
116115
f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod"),
117116
false,
118-
func(m fieldmanager.Manager) fieldmanager.Manager {
119-
return fieldmanager.NewCapManagersManager(m, 3)
117+
func(m Manager) Manager {
118+
return NewCapManagersManager(m, 3)
120119
})
121120

122121
set := func(fields ...string) *metav1.FieldsV1 {

staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager.go

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"k8s.io/apimachinery/pkg/runtime/schema"
2828
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal"
2929
"k8s.io/klog/v2"
30-
openapiproto "k8s.io/kube-openapi/pkg/util/proto"
3130
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
3231
"sigs.k8s.io/structured-merge-diff/v4/merge"
3332
)
@@ -79,12 +78,7 @@ func NewFieldManager(f Manager, ignoreManagedFieldsFromRequestObject bool) *Fiel
7978

8079
// NewDefaultFieldManager creates a new FieldManager that merges apply requests
8180
// and update managed fields for other types of requests.
82-
func NewDefaultFieldManager(models openapiproto.Models, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, ignoreManagedFieldsFromRequestObject bool) (*FieldManager, error) {
83-
typeConverter, err := internal.NewTypeConverter(models, false)
84-
if err != nil {
85-
return nil, err
86-
}
87-
81+
func NewDefaultFieldManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, ignoreManagedFieldsFromRequestObject bool) (*FieldManager, error) {
8882
f, err := NewStructuredMergeManager(typeConverter, objectConverter, objectDefaulter, kind.GroupVersion(), hub)
8983
if err != nil {
9084
return nil, fmt.Errorf("failed to create field manager: %v", err)
@@ -95,23 +89,16 @@ func NewDefaultFieldManager(models openapiproto.Models, objectConverter runtime.
9589
// NewDefaultCRDFieldManager creates a new FieldManager specifically for
9690
// CRDs. This allows for the possibility of fields which are not defined
9791
// in models, as well as having no models defined at all.
98-
func NewDefaultCRDFieldManager(models openapiproto.Models, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, preserveUnknownFields, ignoreManagedFieldsFromRequestObject bool) (_ *FieldManager, err error) {
99-
var typeConverter internal.TypeConverter = internal.DeducedTypeConverter{}
100-
if models != nil {
101-
typeConverter, err = internal.NewTypeConverter(models, preserveUnknownFields)
102-
if err != nil {
103-
return nil, err
104-
}
105-
}
106-
f, err := NewCRDStructuredMergeManager(typeConverter, objectConverter, objectDefaulter, kind.GroupVersion(), hub, preserveUnknownFields)
92+
func NewDefaultCRDFieldManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, ignoreManagedFieldsFromRequestObject bool) (_ *FieldManager, err error) {
93+
f, err := NewCRDStructuredMergeManager(typeConverter, objectConverter, objectDefaulter, kind.GroupVersion(), hub)
10794
if err != nil {
10895
return nil, fmt.Errorf("failed to create field manager: %v", err)
10996
}
11097
return newDefaultFieldManager(f, typeConverter, objectConverter, objectCreater, kind, ignoreManagedFieldsFromRequestObject), nil
11198
}
11299

113100
// newDefaultFieldManager is a helper function which wraps a Manager with certain default logic.
114-
func newDefaultFieldManager(f Manager, typeConverter internal.TypeConverter, objectConverter runtime.ObjectConvertor, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, ignoreManagedFieldsFromRequestObject bool) *FieldManager {
101+
func newDefaultFieldManager(f Manager, typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, ignoreManagedFieldsFromRequestObject bool) *FieldManager {
115102
f = NewStripMetaManager(f)
116103
f = NewManagedFieldsUpdater(f)
117104
f = NewBuildManagerInfoManager(f, kind.GroupVersion())

staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager_test.go

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package fieldmanager_test
17+
package fieldmanager
1818

1919
import (
2020
"errors"
@@ -36,8 +36,6 @@ import (
3636
"k8s.io/apimachinery/pkg/runtime/schema"
3737
"k8s.io/apimachinery/pkg/runtime/serializer"
3838
yamlutil "k8s.io/apimachinery/pkg/util/yaml"
39-
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
40-
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal"
4139
"k8s.io/kube-openapi/pkg/util/proto"
4240
prototesting "k8s.io/kube-openapi/pkg/util/proto/testing"
4341
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
@@ -46,7 +44,7 @@ import (
4644
"sigs.k8s.io/yaml"
4745
)
4846

49-
var fakeSchema = prototesting.Fake{
47+
var kubernetesSwaggerSchema = prototesting.Fake{
5048
Path: filepath.Join(
5149
strings.Repeat(".."+string(filepath.Separator), 8),
5250
"api", "openapi-spec", "swagger.json"),
@@ -80,7 +78,7 @@ type fakeObjectDefaulter struct{}
8078
func (d *fakeObjectDefaulter) Default(in runtime.Object) {}
8179

8280
type TestFieldManager struct {
83-
fieldManager *fieldmanager.FieldManager
81+
fieldManager *FieldManager
8482
emptyObj runtime.Object
8583
liveObj runtime.Object
8684
}
@@ -93,13 +91,13 @@ func NewSubresourceTestFieldManager(gvk schema.GroupVersionKind) TestFieldManage
9391
return NewTestFieldManager(gvk, true, nil)
9492
}
9593

96-
func NewTestFieldManager(gvk schema.GroupVersionKind, ignoreManagedFieldsFromRequestObject bool, chainFieldManager func(fieldmanager.Manager) fieldmanager.Manager) TestFieldManager {
94+
func NewTestFieldManager(gvk schema.GroupVersionKind, ignoreManagedFieldsFromRequestObject bool, chainFieldManager func(Manager) Manager) TestFieldManager {
9795
m := NewFakeOpenAPIModels()
9896
typeConverter := NewFakeTypeConverter(m)
99-
converter := internal.NewVersionConverter(typeConverter, &fakeObjectConvertor{}, gvk.GroupVersion())
97+
converter := newVersionConverter(typeConverter, &fakeObjectConvertor{}, gvk.GroupVersion())
10098
apiVersion := fieldpath.APIVersion(gvk.GroupVersion().String())
10199
objectConverter := &fakeObjectConvertor{converter, apiVersion}
102-
f, err := fieldmanager.NewStructuredMergeManager(
100+
f, err := NewStructuredMergeManager(
103101
typeConverter,
104102
objectConverter,
105103
&fakeObjectDefaulter{},
@@ -112,32 +110,32 @@ func NewTestFieldManager(gvk schema.GroupVersionKind, ignoreManagedFieldsFromReq
112110
live := &unstructured.Unstructured{}
113111
live.SetKind(gvk.Kind)
114112
live.SetAPIVersion(gvk.GroupVersion().String())
115-
f = fieldmanager.NewStripMetaManager(f)
116-
f = fieldmanager.NewManagedFieldsUpdater(f)
117-
f = fieldmanager.NewBuildManagerInfoManager(f, gvk.GroupVersion())
118-
f = fieldmanager.NewProbabilisticSkipNonAppliedManager(f, &fakeObjectCreater{gvk: gvk}, gvk, fieldmanager.DefaultTrackOnCreateProbability)
119-
f = fieldmanager.NewLastAppliedManager(f, typeConverter, objectConverter, gvk.GroupVersion())
120-
f = fieldmanager.NewLastAppliedUpdater(f)
113+
f = NewStripMetaManager(f)
114+
f = NewManagedFieldsUpdater(f)
115+
f = NewBuildManagerInfoManager(f, gvk.GroupVersion())
116+
f = NewProbabilisticSkipNonAppliedManager(f, &fakeObjectCreater{gvk: gvk}, gvk, DefaultTrackOnCreateProbability)
117+
f = NewLastAppliedManager(f, typeConverter, objectConverter, gvk.GroupVersion())
118+
f = NewLastAppliedUpdater(f)
121119
if chainFieldManager != nil {
122120
f = chainFieldManager(f)
123121
}
124122
return TestFieldManager{
125-
fieldManager: fieldmanager.NewFieldManager(f, ignoreManagedFieldsFromRequestObject),
123+
fieldManager: NewFieldManager(f, ignoreManagedFieldsFromRequestObject),
126124
emptyObj: live,
127125
liveObj: live.DeepCopyObject(),
128126
}
129127
}
130128

131-
func NewFakeTypeConverter(m proto.Models) internal.TypeConverter {
132-
tc, err := internal.NewTypeConverter(m, false)
129+
func NewFakeTypeConverter(m proto.Models) TypeConverter {
130+
tc, err := NewTypeConverter(m, false)
133131
if err != nil {
134132
panic(fmt.Sprintf("Failed to build TypeConverter: %v", err))
135133
}
136134
return tc
137135
}
138136

139137
func NewFakeOpenAPIModels() proto.Models {
140-
d, err := fakeSchema.OpenAPISchema()
138+
d, err := kubernetesSwaggerSchema.OpenAPISchema()
141139
if err != nil {
142140
panic(err)
143141
}
@@ -1207,20 +1205,6 @@ func setLastAppliedFromEncoded(obj runtime.Object, lastApplied []byte) error {
12071205
return setLastApplied(obj, lastAppliedJSON)
12081206
}
12091207

1210-
func setLastApplied(obj runtime.Object, lastApplied string) error {
1211-
accessor := meta.NewAccessor()
1212-
annotations, err := accessor.Annotations(obj)
1213-
if err != nil {
1214-
return fmt.Errorf("failed to access annotations: %v", err)
1215-
}
1216-
if annotations == nil {
1217-
annotations = map[string]string{}
1218-
}
1219-
annotations[corev1.LastAppliedConfigAnnotation] = lastApplied
1220-
accessor.SetAnnotations(obj, annotations)
1221-
return nil
1222-
}
1223-
12241208
func getLastApplied(obj runtime.Object) (string, error) {
12251209
accessor := meta.NewAccessor()
12261210
annotations, err := accessor.Annotations(obj)

staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/BUILD

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ go_library(
99
"gvkparser.go",
1010
"managedfields.go",
1111
"pathelement.go",
12-
"typeconverter.go",
13-
"versionconverter.go",
1412
],
1513
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal",
1614
importpath = "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal",
@@ -19,7 +17,6 @@ go_library(
1917
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
2018
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
2119
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
22-
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
2320
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
2421
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
2522
"//vendor/k8s.io/kube-openapi/pkg/schemaconv:go_default_library",
@@ -39,22 +36,14 @@ go_test(
3936
"fields_test.go",
4037
"managedfields_test.go",
4138
"pathelement_test.go",
42-
"typeconverter_test.go",
43-
"versionconverter_test.go",
4439
],
4540
data = glob(["testdata/**"]),
4641
embed = [":go_default_library"],
4742
deps = [
4843
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
4944
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
50-
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
51-
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
52-
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
53-
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
54-
"//vendor/k8s.io/kube-openapi/pkg/util/proto/testing:go_default_library",
5545
"//vendor/sigs.k8s.io/structured-merge-diff/v4/fieldpath:go_default_library",
5646
"//vendor/sigs.k8s.io/structured-merge-diff/v4/merge:go_default_library",
57-
"//vendor/sigs.k8s.io/structured-merge-diff/v4/typed:go_default_library",
5847
"//vendor/sigs.k8s.io/yaml:go_default_library",
5948
],
6049
)

staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/gvkparser.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,15 @@ import (
3030
// definition's "extensions" map.
3131
const groupVersionKindExtensionKey = "x-kubernetes-group-version-kind"
3232

33-
type gvkParser struct {
33+
// GvkParser contains a Parser that allows introspecting the schema.
34+
type GvkParser struct {
3435
gvks map[schema.GroupVersionKind]string
3536
parser typed.Parser
3637
}
3738

38-
func (p *gvkParser) Type(gvk schema.GroupVersionKind) *typed.ParseableType {
39+
// Type returns a helper which can produce objects of the given type. Any
40+
// errors are deferred until a further function is called.
41+
func (p *GvkParser) Type(gvk schema.GroupVersionKind) *typed.ParseableType {
3942
typeName, ok := p.gvks[gvk]
4043
if !ok {
4144
return nil
@@ -44,12 +47,15 @@ func (p *gvkParser) Type(gvk schema.GroupVersionKind) *typed.ParseableType {
4447
return &t
4548
}
4649

47-
func newGVKParser(models proto.Models, preserveUnknownFields bool) (*gvkParser, error) {
50+
// NewGVKParser builds a GVKParser from a proto.Models. This
51+
// will automatically find the proper version of the object, and the
52+
// corresponding schema information.
53+
func NewGVKParser(models proto.Models, preserveUnknownFields bool) (*GvkParser, error) {
4854
typeSchema, err := schemaconv.ToSchemaWithPreserveUnknownFields(models, preserveUnknownFields)
4955
if err != nil {
5056
return nil, fmt.Errorf("failed to convert models to schema: %v", err)
5157
}
52-
parser := gvkParser{
58+
parser := GvkParser{
5359
gvks: map[schema.GroupVersionKind]string{},
5460
}
5561
parser.parser = typed.Parser{Schema: *typeSchema}

0 commit comments

Comments
 (0)