mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 21:47:07 +00:00
Ensure patched objects are defaulted correctly
This commit is contained in:
parent
18ffc95308
commit
464db160b4
1
pkg/master/thirdparty/thirdparty.go
vendored
1
pkg/master/thirdparty/thirdparty.go
vendored
@ -318,6 +318,7 @@ func (m *ThirdPartyResourceServer) thirdpartyapi(group, kind, version, pluralRes
|
|||||||
Creater: thirdpartyresourcedata.NewObjectCreator(group, version, api.Scheme),
|
Creater: thirdpartyresourcedata.NewObjectCreator(group, version, api.Scheme),
|
||||||
Convertor: api.Scheme,
|
Convertor: api.Scheme,
|
||||||
Copier: api.Scheme,
|
Copier: api.Scheme,
|
||||||
|
Defaulter: api.Scheme,
|
||||||
Typer: api.Scheme,
|
Typer: api.Scheme,
|
||||||
|
|
||||||
Mapper: thirdpartyresourcedata.NewMapper(api.Registry.GroupOrDie(extensions.GroupName).RESTMapper, kind, version, group),
|
Mapper: thirdpartyresourcedata.NewMapper(api.Registry.GroupOrDie(extensions.GroupName).RESTMapper, kind, version, group),
|
||||||
|
@ -284,6 +284,7 @@ func handleInternal(storage map[string]rest.Storage, admissionControl admission.
|
|||||||
Creater: scheme,
|
Creater: scheme,
|
||||||
Convertor: scheme,
|
Convertor: scheme,
|
||||||
Copier: scheme,
|
Copier: scheme,
|
||||||
|
Defaulter: scheme,
|
||||||
Typer: scheme,
|
Typer: scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
Mapper: namespaceMapper,
|
Mapper: namespaceMapper,
|
||||||
@ -2579,6 +2580,7 @@ func TestUpdateREST(t *testing.T) {
|
|||||||
Creater: scheme,
|
Creater: scheme,
|
||||||
Convertor: scheme,
|
Convertor: scheme,
|
||||||
Copier: scheme,
|
Copier: scheme,
|
||||||
|
Defaulter: scheme,
|
||||||
Typer: scheme,
|
Typer: scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
|
|
||||||
@ -2663,6 +2665,7 @@ func TestParentResourceIsRequired(t *testing.T) {
|
|||||||
Creater: scheme,
|
Creater: scheme,
|
||||||
Convertor: scheme,
|
Convertor: scheme,
|
||||||
Copier: scheme,
|
Copier: scheme,
|
||||||
|
Defaulter: scheme,
|
||||||
Typer: scheme,
|
Typer: scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
|
|
||||||
@ -2694,6 +2697,7 @@ func TestParentResourceIsRequired(t *testing.T) {
|
|||||||
Creater: scheme,
|
Creater: scheme,
|
||||||
Convertor: scheme,
|
Convertor: scheme,
|
||||||
Copier: scheme,
|
Copier: scheme,
|
||||||
|
Defaulter: scheme,
|
||||||
Typer: scheme,
|
Typer: scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
|
|
||||||
@ -3307,6 +3311,7 @@ func TestXGSubresource(t *testing.T) {
|
|||||||
Creater: scheme,
|
Creater: scheme,
|
||||||
Convertor: scheme,
|
Convertor: scheme,
|
||||||
Copier: scheme,
|
Copier: scheme,
|
||||||
|
Defaulter: scheme,
|
||||||
Typer: scheme,
|
Typer: scheme,
|
||||||
Linker: selfLinker,
|
Linker: selfLinker,
|
||||||
Mapper: namespaceMapper,
|
Mapper: namespaceMapper,
|
||||||
|
@ -69,6 +69,7 @@ type APIGroupVersion struct {
|
|||||||
Creater runtime.ObjectCreater
|
Creater runtime.ObjectCreater
|
||||||
Convertor runtime.ObjectConvertor
|
Convertor runtime.ObjectConvertor
|
||||||
Copier runtime.ObjectCopier
|
Copier runtime.ObjectCopier
|
||||||
|
Defaulter runtime.ObjectDefaulter
|
||||||
Linker runtime.SelfLinker
|
Linker runtime.SelfLinker
|
||||||
UnsafeConvertor runtime.ObjectConvertor
|
UnsafeConvertor runtime.ObjectConvertor
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@ func patchObjectJSON(
|
|||||||
// NOTE: Both <originalObject> and <objToUpdate> are supposed to be versioned.
|
// NOTE: Both <originalObject> and <objToUpdate> are supposed to be versioned.
|
||||||
func strategicPatchObject(
|
func strategicPatchObject(
|
||||||
codec runtime.Codec,
|
codec runtime.Codec,
|
||||||
|
defaulter runtime.ObjectDefaulter,
|
||||||
originalObject runtime.Object,
|
originalObject runtime.Object,
|
||||||
patchJS []byte,
|
patchJS []byte,
|
||||||
objToUpdate runtime.Object,
|
objToUpdate runtime.Object,
|
||||||
@ -96,17 +97,18 @@ func strategicPatchObject(
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := applyPatchToObject(codec, originalObjMap, patchMap, objToUpdate, versionedObj); err != nil {
|
if err := applyPatchToObject(codec, defaulter, originalObjMap, patchMap, objToUpdate, versionedObj); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyPatchToObject applies a strategic merge patch of <patchMap> to
|
// applyPatchToObject applies a strategic merge patch of <patchMap> to
|
||||||
// <originalMap> and stores the result in <objToUpdate>, though it operates
|
// <originalMap> and stores the result in <objToUpdate>.
|
||||||
// on versioned map[string]interface{} representations.
|
// NOTE: <objToUpdate> must be a versioned object.
|
||||||
func applyPatchToObject(
|
func applyPatchToObject(
|
||||||
codec runtime.Codec,
|
codec runtime.Codec,
|
||||||
|
defaulter runtime.ObjectDefaulter,
|
||||||
originalMap map[string]interface{},
|
originalMap map[string]interface{},
|
||||||
patchMap map[string]interface{},
|
patchMap map[string]interface{},
|
||||||
objToUpdate runtime.Object,
|
objToUpdate runtime.Object,
|
||||||
@ -117,5 +119,12 @@ func applyPatchToObject(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return unstructured.DefaultConverter.FromUnstructured(patchedObjMap, objToUpdate)
|
// Rather than serialize the patched map to JSON, then decode it to an object, we go directly from a map to an object
|
||||||
|
if err := unstructured.DefaultConverter.FromUnstructured(patchedObjMap, objToUpdate); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Decoding from JSON to a versioned object would apply defaults, so we do the same here
|
||||||
|
defaulter.Default(objToUpdate)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,7 @@ type RequestScope struct {
|
|||||||
|
|
||||||
Creater runtime.ObjectCreater
|
Creater runtime.ObjectCreater
|
||||||
Convertor runtime.ObjectConvertor
|
Convertor runtime.ObjectConvertor
|
||||||
|
Defaulter runtime.ObjectDefaulter
|
||||||
Copier runtime.ObjectCopier
|
Copier runtime.ObjectCopier
|
||||||
Typer runtime.ObjectTyper
|
Typer runtime.ObjectTyper
|
||||||
UnsafeConvertor runtime.ObjectConvertor
|
UnsafeConvertor runtime.ObjectConvertor
|
||||||
@ -525,7 +526,7 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
|
|||||||
}
|
}
|
||||||
|
|
||||||
result, err := patchResource(ctx, updateAdmit, timeout, versionedObj, r, name, patchType, patchJS,
|
result, err := patchResource(ctx, updateAdmit, timeout, versionedObj, r, name, patchType, patchJS,
|
||||||
scope.Namer, scope.Copier, scope.Creater, scope.UnsafeConvertor, scope.Kind, scope.Resource, codec)
|
scope.Namer, scope.Copier, scope.Creater, scope.Defaulter, scope.UnsafeConvertor, scope.Kind, scope.Resource, codec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, res.ResponseWriter, req.Request)
|
scope.err(err, res.ResponseWriter, req.Request)
|
||||||
return
|
return
|
||||||
@ -556,6 +557,7 @@ func patchResource(
|
|||||||
namer ScopeNamer,
|
namer ScopeNamer,
|
||||||
copier runtime.ObjectCopier,
|
copier runtime.ObjectCopier,
|
||||||
creater runtime.ObjectCreater,
|
creater runtime.ObjectCreater,
|
||||||
|
defaulter runtime.ObjectDefaulter,
|
||||||
unsafeConvertor runtime.ObjectConvertor,
|
unsafeConvertor runtime.ObjectConvertor,
|
||||||
kind schema.GroupVersionKind,
|
kind schema.GroupVersionKind,
|
||||||
resource schema.GroupVersionResource,
|
resource schema.GroupVersionResource,
|
||||||
@ -619,7 +621,7 @@ func patchResource(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
originalMap, patchMap, err := strategicPatchObject(codec, currentVersionedObject, patchJS, versionedObjToUpdate, versionedObj)
|
originalMap, patchMap, err := strategicPatchObject(codec, defaulter, currentVersionedObject, patchJS, versionedObjToUpdate, versionedObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -716,7 +718,7 @@ func patchResource(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := applyPatchToObject(codec, currentObjMap, originalPatchMap, versionedObjToUpdate, versionedObj); err != nil {
|
if err := applyPatchToObject(codec, defaulter, currentObjMap, originalPatchMap, versionedObjToUpdate, versionedObj); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Convert the object back to unversioned.
|
// Convert the object back to unversioned.
|
||||||
|
@ -61,6 +61,7 @@ func TestPatchAnonymousField(t *testing.T) {
|
|||||||
testGV := schema.GroupVersion{Group: "", Version: "v"}
|
testGV := schema.GroupVersion{Group: "", Version: "v"}
|
||||||
api.Scheme.AddKnownTypes(testGV, &testPatchType{})
|
api.Scheme.AddKnownTypes(testGV, &testPatchType{})
|
||||||
codec := api.Codecs.LegacyCodec(testGV)
|
codec := api.Codecs.LegacyCodec(testGV)
|
||||||
|
defaulter := runtime.ObjectDefaulter(api.Scheme)
|
||||||
|
|
||||||
original := &testPatchType{
|
original := &testPatchType{
|
||||||
TypeMeta: metav1.TypeMeta{Kind: "testPatchType", APIVersion: "v"},
|
TypeMeta: metav1.TypeMeta{Kind: "testPatchType", APIVersion: "v"},
|
||||||
@ -73,7 +74,7 @@ func TestPatchAnonymousField(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
actual := &testPatchType{}
|
actual := &testPatchType{}
|
||||||
_, _, err := strategicPatchObject(codec, original, []byte(patch), actual, &testPatchType{})
|
_, _, err := strategicPatchObject(codec, defaulter, original, []byte(patch), actual, &testPatchType{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -203,6 +204,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
namer := &testNamer{namespace, name}
|
namer := &testNamer{namespace, name}
|
||||||
copier := runtime.ObjectCopier(api.Scheme)
|
copier := runtime.ObjectCopier(api.Scheme)
|
||||||
creater := runtime.ObjectCreater(api.Scheme)
|
creater := runtime.ObjectCreater(api.Scheme)
|
||||||
|
defaulter := runtime.ObjectDefaulter(api.Scheme)
|
||||||
convertor := runtime.UnsafeObjectConvertor(api.Scheme)
|
convertor := runtime.UnsafeObjectConvertor(api.Scheme)
|
||||||
kind := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
|
kind := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}
|
||||||
resource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
resource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
||||||
@ -247,7 +249,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resultObj, err := patchResource(ctx, admit, 1*time.Second, versionedObj, testPatcher, name, patchType, patch, namer, copier, creater, convertor, kind, resource, codec)
|
resultObj, err := patchResource(ctx, admit, 1*time.Second, versionedObj, testPatcher, name, patchType, patch, namer, copier, creater, defaulter, convertor, kind, resource, codec)
|
||||||
if len(tc.expectedError) != 0 {
|
if len(tc.expectedError) != 0 {
|
||||||
if err == nil || err.Error() != tc.expectedError {
|
if err == nil || err.Error() != tc.expectedError {
|
||||||
t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err)
|
t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err)
|
||||||
@ -269,12 +271,18 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
|
|
||||||
resultPod := resultObj.(*api.Pod)
|
resultPod := resultObj.(*api.Pod)
|
||||||
|
|
||||||
// TODO: In the process of applying patches, we are calling
|
// roundtrip to get defaulting
|
||||||
// conversions between versioned and unversioned objects.
|
expectedJS, err := runtime.Encode(codec, tc.expectedPod)
|
||||||
// In case of Pod, conversion from versioned to unversioned
|
if err != nil {
|
||||||
// is setting PodSecurityContext, so we need to set it here too.
|
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||||
reallyExpectedPod := tc.expectedPod
|
return
|
||||||
reallyExpectedPod.Spec.SecurityContext = &api.PodSecurityContext{}
|
}
|
||||||
|
expectedObj, err := runtime.Decode(codec, expectedJS)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reallyExpectedPod := expectedObj.(*api.Pod)
|
||||||
|
|
||||||
if !reflect.DeepEqual(*reallyExpectedPod, *resultPod) {
|
if !reflect.DeepEqual(*reallyExpectedPod, *resultPod) {
|
||||||
t.Errorf("%s mismatch: %v\n", tc.name, diff.ObjectGoPrintDiff(reallyExpectedPod, resultPod))
|
t.Errorf("%s mismatch: %v\n", tc.name, diff.ObjectGoPrintDiff(reallyExpectedPod, resultPod))
|
||||||
@ -286,6 +294,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
|
|
||||||
func TestNumberConversion(t *testing.T) {
|
func TestNumberConversion(t *testing.T) {
|
||||||
codec := api.Codecs.LegacyCodec(schema.GroupVersion{Version: "v1"})
|
codec := api.Codecs.LegacyCodec(schema.GroupVersion{Version: "v1"})
|
||||||
|
defaulter := runtime.ObjectDefaulter(api.Scheme)
|
||||||
|
|
||||||
currentVersionedObject := &v1.Service{
|
currentVersionedObject := &v1.Service{
|
||||||
TypeMeta: metav1.TypeMeta{Kind: "Service", APIVersion: "v1"},
|
TypeMeta: metav1.TypeMeta{Kind: "Service", APIVersion: "v1"},
|
||||||
@ -305,7 +314,7 @@ func TestNumberConversion(t *testing.T) {
|
|||||||
|
|
||||||
patchJS := []byte(`{"spec":{"ports":[{"port":80,"nodePort":31789}]}}`)
|
patchJS := []byte(`{"spec":{"ports":[{"port":80,"nodePort":31789}]}}`)
|
||||||
|
|
||||||
_, _, err := strategicPatchObject(codec, currentVersionedObject, patchJS, versionedObjToUpdate, versionedObj)
|
_, _, err := strategicPatchObject(codec, defaulter, currentVersionedObject, patchJS, versionedObjToUpdate, versionedObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -522,6 +522,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
Creater: a.group.Creater,
|
Creater: a.group.Creater,
|
||||||
Convertor: a.group.Convertor,
|
Convertor: a.group.Convertor,
|
||||||
Copier: a.group.Copier,
|
Copier: a.group.Copier,
|
||||||
|
Defaulter: a.group.Defaulter,
|
||||||
Typer: a.group.Typer,
|
Typer: a.group.Typer,
|
||||||
UnsafeConvertor: a.group.UnsafeConvertor,
|
UnsafeConvertor: a.group.UnsafeConvertor,
|
||||||
|
|
||||||
|
@ -366,6 +366,7 @@ func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV
|
|||||||
Convertor: apiGroupInfo.Scheme,
|
Convertor: apiGroupInfo.Scheme,
|
||||||
UnsafeConvertor: runtime.UnsafeObjectConvertor(apiGroupInfo.Scheme),
|
UnsafeConvertor: runtime.UnsafeObjectConvertor(apiGroupInfo.Scheme),
|
||||||
Copier: apiGroupInfo.Scheme,
|
Copier: apiGroupInfo.Scheme,
|
||||||
|
Defaulter: apiGroupInfo.Scheme,
|
||||||
Typer: apiGroupInfo.Scheme,
|
Typer: apiGroupInfo.Scheme,
|
||||||
SubresourceGroupVersionKind: apiGroupInfo.SubresourceGroupVersionKind,
|
SubresourceGroupVersionKind: apiGroupInfo.SubresourceGroupVersionKind,
|
||||||
Linker: apiGroupInfo.GroupMeta.SelfLinker,
|
Linker: apiGroupInfo.GroupMeta.SelfLinker,
|
||||||
|
Loading…
Reference in New Issue
Block a user