mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-20 10:20:51 +00:00
Merge pull request #86560 from kwiesmueller/change-apply-signature
change apply signature and move it's decoding into handler
This commit is contained in:
commit
4a55a5557e
@ -70,6 +70,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1beta1/validation:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1beta1/validation:go_default_library",
|
||||||
@ -104,6 +105,7 @@ go_library(
|
|||||||
"//vendor/golang.org/x/net/websocket:go_default_library",
|
"//vendor/golang.org/x/net/websocket:go_default_library",
|
||||||
"//vendor/k8s.io/klog:go_default_library",
|
"//vendor/k8s.io/klog:go_default_library",
|
||||||
"//vendor/k8s.io/utils/trace:go_default_library",
|
"//vendor/k8s.io/utils/trace:go_default_library",
|
||||||
|
"//vendor/sigs.k8s.io/yaml:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal:go_default_library",
|
||||||
@ -25,7 +24,6 @@ go_library(
|
|||||||
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
|
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
|
||||||
"//vendor/sigs.k8s.io/structured-merge-diff/fieldpath:go_default_library",
|
"//vendor/sigs.k8s.io/structured-merge-diff/fieldpath:go_default_library",
|
||||||
"//vendor/sigs.k8s.io/structured-merge-diff/merge:go_default_library",
|
"//vendor/sigs.k8s.io/structured-merge-diff/merge:go_default_library",
|
||||||
"//vendor/sigs.k8s.io/yaml:go_default_library",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,12 +51,12 @@ func (f *buildManagerInfoManager) Update(liveObj, newObj runtime.Object, managed
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Manager.
|
// Apply implements Manager.
|
||||||
func (f *buildManagerInfoManager) Apply(liveObj runtime.Object, patch []byte, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
func (f *buildManagerInfoManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
||||||
manager, err := f.buildManagerInfo(manager, metav1.ManagedFieldsOperationApply)
|
manager, err := f.buildManagerInfo(manager, metav1.ManagedFieldsOperationApply)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to build manager identifier: %v", err)
|
return nil, nil, fmt.Errorf("failed to build manager identifier: %v", err)
|
||||||
}
|
}
|
||||||
return f.fieldManager.Apply(liveObj, patch, managed, manager, force)
|
return f.fieldManager.Apply(liveObj, appliedObj, managed, manager, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *buildManagerInfoManager) buildManagerInfo(prefix string, operation metav1.ManagedFieldsOperationType) (string, error) {
|
func (f *buildManagerInfoManager) buildManagerInfo(prefix string, operation metav1.ManagedFieldsOperationType) (string, error) {
|
||||||
|
@ -58,8 +58,8 @@ func (f *capManagersManager) Update(liveObj, newObj runtime.Object, managed Mana
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Manager.
|
// Apply implements Manager.
|
||||||
func (f *capManagersManager) Apply(liveObj runtime.Object, patch []byte, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) {
|
func (f *capManagersManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) {
|
||||||
return f.fieldManager.Apply(liveObj, patch, managed, fieldManager, force)
|
return f.fieldManager.Apply(liveObj, appliedObj, managed, fieldManager, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
// capUpdateManagers merges a number of the oldest update entries into versioned buckets,
|
// capUpdateManagers merges a number of the oldest update entries into versioned buckets,
|
||||||
|
@ -41,7 +41,7 @@ func (*fakeManager) Update(_, newObj runtime.Object, managed fieldmanager.Manage
|
|||||||
return newObj, managed, nil
|
return newObj, managed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*fakeManager) Apply(_ runtime.Object, _ []byte, _ fieldmanager.Managed, _ string, force bool) (runtime.Object, fieldmanager.Managed, error) {
|
func (*fakeManager) Apply(_, _ runtime.Object, _ fieldmanager.Managed, _ string, force bool) (runtime.Object, fieldmanager.Managed, error) {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ type Manager interface {
|
|||||||
|
|
||||||
// Apply is used when server-side apply is called, as it merges the
|
// Apply is used when server-side apply is called, as it merges the
|
||||||
// object and updates the managed fields.
|
// object and updates the managed fields.
|
||||||
Apply(liveObj runtime.Object, patch []byte, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error)
|
Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FieldManager updates the managed fields and merge applied
|
// FieldManager updates the managed fields and merge applied
|
||||||
@ -135,7 +135,7 @@ func (f *FieldManager) Update(liveObj, newObj runtime.Object, manager string) (o
|
|||||||
|
|
||||||
// Apply is used when server-side apply is called, as it merges the
|
// Apply is used when server-side apply is called, as it merges the
|
||||||
// object and updates the managed fields.
|
// object and updates the managed fields.
|
||||||
func (f *FieldManager) Apply(liveObj runtime.Object, patch []byte, manager string, force bool) (object runtime.Object, err error) {
|
func (f *FieldManager) Apply(liveObj, appliedObj runtime.Object, manager string, force bool) (object runtime.Object, err error) {
|
||||||
// If the object doesn't have metadata, apply isn't allowed.
|
// If the object doesn't have metadata, apply isn't allowed.
|
||||||
if _, err = meta.Accessor(liveObj); err != nil {
|
if _, err = meta.Accessor(liveObj); err != nil {
|
||||||
return nil, fmt.Errorf("couldn't get accessor: %v", err)
|
return nil, fmt.Errorf("couldn't get accessor: %v", err)
|
||||||
@ -149,7 +149,7 @@ func (f *FieldManager) Apply(liveObj runtime.Object, patch []byte, manager strin
|
|||||||
|
|
||||||
internal.RemoveObjectManagedFields(liveObj)
|
internal.RemoveObjectManagedFields(liveObj)
|
||||||
|
|
||||||
if object, managed, err = f.fieldManager.Apply(liveObj, patch, managed, manager, force); err != nil {
|
if object, managed, err = f.fieldManager.Apply(liveObj, appliedObj, managed, manager, force); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ func (f *TestFieldManager) Reset() {
|
|||||||
f.liveObj = f.emptyObj.DeepCopyObject()
|
f.liveObj = f.emptyObj.DeepCopyObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TestFieldManager) Apply(obj []byte, manager string, force bool) error {
|
func (f *TestFieldManager) Apply(obj runtime.Object, manager string, force bool) error {
|
||||||
out, err := fieldmanager.NewFieldManager(f.fieldManager).Apply(f.liveObj, obj, manager, force)
|
out, err := fieldmanager.NewFieldManager(f.fieldManager).Apply(f.liveObj, obj, manager, force)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
f.liveObj = out
|
f.liveObj = out
|
||||||
@ -174,7 +174,8 @@ func TestUpdateApplyConflict(t *testing.T) {
|
|||||||
t.Fatalf("failed to apply object: %v", err)
|
t.Fatalf("failed to apply object: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := f.Apply([]byte(`{
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
@ -183,7 +184,11 @@ func TestUpdateApplyConflict(t *testing.T) {
|
|||||||
"spec": {
|
"spec": {
|
||||||
"replicas": 101,
|
"replicas": 101,
|
||||||
}
|
}
|
||||||
}`), "fieldmanager_conflict", false)
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := f.Apply(appliedObj, "fieldmanager_conflict", false)
|
||||||
if err == nil || !apierrors.IsConflict(err) {
|
if err == nil || !apierrors.IsConflict(err) {
|
||||||
t.Fatalf("Expecting to get conflicts but got %v", err)
|
t.Fatalf("Expecting to get conflicts but got %v", err)
|
||||||
}
|
}
|
||||||
@ -225,20 +230,68 @@ func TestApplyStripsFields(t *testing.T) {
|
|||||||
func TestVersionCheck(t *testing.T) {
|
func TestVersionCheck(t *testing.T) {
|
||||||
f := NewTestFieldManager(schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
|
f := NewTestFieldManager(schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
|
||||||
|
|
||||||
// patch has 'apiVersion: apps/v1' and live version is apps/v1 -> no errors
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
err := f.Apply([]byte(`{
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
}`), "fieldmanager_test", false)
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch has 'apiVersion: apps/v1' and live version is apps/v1 -> no errors
|
||||||
|
err := f.Apply(appliedObj, "fieldmanager_test", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to apply object: %v", err)
|
t.Fatalf("failed to apply object: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// patch has 'apiVersion: apps/v2' but live version is apps/v1 -> error
|
appliedObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
err = f.Apply([]byte(`{
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
"apiVersion": "apps/v1beta1",
|
"apiVersion": "apps/v1beta1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
}`), "fieldmanager_test", false)
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch has 'apiVersion: apps/v2' but live version is apps/v1 -> error
|
||||||
|
err = f.Apply(appliedObj, "fieldmanager_test", false)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected an error from mismatched patch and live versions")
|
||||||
|
}
|
||||||
|
switch typ := err.(type) {
|
||||||
|
default:
|
||||||
|
t.Fatalf("expected error to be of type %T was %T", apierrors.StatusError{}, typ)
|
||||||
|
case apierrors.APIStatus:
|
||||||
|
if typ.Status().Code != http.StatusBadRequest {
|
||||||
|
t.Fatalf("expected status code to be %d but was %d",
|
||||||
|
http.StatusBadRequest, typ.Status().Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestVersionCheckDoesNotPanic(t *testing.T) {
|
||||||
|
f := NewTestFieldManager(schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
|
||||||
|
|
||||||
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch has 'apiVersion: apps/v1' and live version is apps/v1 -> no errors
|
||||||
|
err := f.Apply(appliedObj, "fieldmanager_test", false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to apply object: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
appliedObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch has 'apiVersion: apps/v2' but live version is apps/v1 -> error
|
||||||
|
err = f.Apply(appliedObj, "fieldmanager_test", false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected an error from mismatched patch and live versions")
|
t.Fatalf("expected an error from mismatched patch and live versions")
|
||||||
}
|
}
|
||||||
@ -256,7 +309,8 @@ func TestVersionCheck(t *testing.T) {
|
|||||||
func TestApplyDoesNotStripLabels(t *testing.T) {
|
func TestApplyDoesNotStripLabels(t *testing.T) {
|
||||||
f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod"))
|
f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod"))
|
||||||
|
|
||||||
err := f.Apply([]byte(`{
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Pod",
|
"kind": "Pod",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
@ -264,7 +318,11 @@ func TestApplyDoesNotStripLabels(t *testing.T) {
|
|||||||
"a": "b"
|
"a": "b"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}`), "fieldmanager_test", false)
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := f.Apply(appliedObj, "fieldmanager_test", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to apply object: %v", err)
|
t.Fatalf("failed to apply object: %v", err)
|
||||||
}
|
}
|
||||||
@ -305,7 +363,12 @@ func TestApplyNewObject(t *testing.T) {
|
|||||||
t.Run(test.gvk.String(), func(t *testing.T) {
|
t.Run(test.gvk.String(), func(t *testing.T) {
|
||||||
f := NewTestFieldManager(test.gvk)
|
f := NewTestFieldManager(test.gvk)
|
||||||
|
|
||||||
if err := f.Apply(test.obj, "fieldmanager_test", false); err != nil {
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal(test.obj, &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Apply(appliedObj, "fieldmanager_test", false); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -362,7 +425,11 @@ func BenchmarkNewObject(b *testing.B) {
|
|||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
err := f.Apply(test.obj, "fieldmanager_test", false)
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal(test.obj, &appliedObj.Object); err != nil {
|
||||||
|
b.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
err := f.Apply(appliedObj, "fieldmanager_test", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -387,7 +454,12 @@ func BenchmarkRepeatedUpdate(b *testing.B) {
|
|||||||
obj.Spec.Containers[0].Image = "nginx:4.3"
|
obj.Spec.Containers[0].Image = "nginx:4.3"
|
||||||
objs = append(objs, obj)
|
objs = append(objs, obj)
|
||||||
|
|
||||||
err := f.Apply(podBytes, "fieldmanager_apply", false)
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal(podBytes, &appliedObj.Object); err != nil {
|
||||||
|
b.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := f.Apply(appliedObj, "fieldmanager_apply", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -410,7 +482,8 @@ func BenchmarkRepeatedUpdate(b *testing.B) {
|
|||||||
func TestApplyFailsWithManagedFields(t *testing.T) {
|
func TestApplyFailsWithManagedFields(t *testing.T) {
|
||||||
f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod"))
|
f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod"))
|
||||||
|
|
||||||
err := f.Apply([]byte(`{
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Pod",
|
"kind": "Pod",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
@ -420,7 +493,11 @@ func TestApplyFailsWithManagedFields(t *testing.T) {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}`), "fieldmanager_test", false)
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := f.Apply(appliedObj, "fieldmanager_test", false)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("successfully applied with set managed fields")
|
t.Fatalf("successfully applied with set managed fields")
|
||||||
@ -430,7 +507,8 @@ func TestApplyFailsWithManagedFields(t *testing.T) {
|
|||||||
func TestApplySuccessWithNoManagedFields(t *testing.T) {
|
func TestApplySuccessWithNoManagedFields(t *testing.T) {
|
||||||
f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod"))
|
f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod"))
|
||||||
|
|
||||||
err := f.Apply([]byte(`{
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Pod",
|
"kind": "Pod",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
@ -438,7 +516,10 @@ func TestApplySuccessWithNoManagedFields(t *testing.T) {
|
|||||||
"a": "b"
|
"a": "b"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}`), "fieldmanager_test", false)
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
err := f.Apply(appliedObj, "fieldmanager_test", false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to apply object: %v", err)
|
t.Fatalf("failed to apply object: %v", err)
|
||||||
|
@ -51,7 +51,7 @@ func (f *skipNonAppliedManager) Update(liveObj, newObj runtime.Object, managed M
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Manager.
|
// Apply implements Manager.
|
||||||
func (f *skipNonAppliedManager) Apply(liveObj runtime.Object, patch []byte, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) {
|
func (f *skipNonAppliedManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) {
|
||||||
if len(managed.Fields()) == 0 {
|
if len(managed.Fields()) == 0 {
|
||||||
emptyObj, err := f.objectCreater.New(f.gvk)
|
emptyObj, err := f.objectCreater.New(f.gvk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -62,5 +62,5 @@ func (f *skipNonAppliedManager) Apply(liveObj runtime.Object, patch []byte, mana
|
|||||||
return nil, nil, fmt.Errorf("failed to create manager for existing fields: %v", err)
|
return nil, nil, fmt.Errorf("failed to create manager for existing fields: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return f.fieldManager.Apply(liveObj, patch, managed, fieldManager, force)
|
return f.fieldManager.Apply(liveObj, appliedObj, managed, fieldManager, force)
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fakeObjectCreater struct {
|
type fakeObjectCreater struct {
|
||||||
@ -49,7 +50,8 @@ func TestNoUpdateBeforeFirstApply(t *testing.T) {
|
|||||||
schema.GroupVersionKind{},
|
schema.GroupVersionKind{},
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := f.Apply([]byte(`{
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Pod",
|
"kind": "Pod",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
@ -62,7 +64,11 @@ func TestNoUpdateBeforeFirstApply(t *testing.T) {
|
|||||||
"image": "nginx:latest"
|
"image": "nginx:latest"
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}`), "fieldmanager_test_apply", false); err != nil {
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Apply(appliedObj, "fieldmanager_test_apply", false); err != nil {
|
||||||
t.Fatalf("failed to update object: %v", err)
|
t.Fatalf("failed to update object: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +102,8 @@ func TestUpdateBeforeFirstApply(t *testing.T) {
|
|||||||
t.Fatalf("managedFields were tracked on update only: %v", m)
|
t.Fatalf("managedFields were tracked on update only: %v", m)
|
||||||
}
|
}
|
||||||
|
|
||||||
appliedBytes := []byte(`{
|
appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal([]byte(`{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Pod",
|
"kind": "Pod",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
@ -109,9 +116,11 @@ func TestUpdateBeforeFirstApply(t *testing.T) {
|
|||||||
"image": "nginx:latest"
|
"image": "nginx:latest"
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}`)
|
}`), &appliedObj.Object); err != nil {
|
||||||
|
t.Fatalf("error decoding YAML: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
err := f.Apply(appliedBytes, "fieldmanager_test_apply", false)
|
err := f.Apply(appliedObj, "fieldmanager_test_apply", false)
|
||||||
apiStatus, _ := err.(apierrors.APIStatus)
|
apiStatus, _ := err.(apierrors.APIStatus)
|
||||||
if err == nil || !apierrors.IsConflict(err) || len(apiStatus.Status().Details.Causes) != 1 {
|
if err == nil || !apierrors.IsConflict(err) || len(apiStatus.Status().Details.Causes) != 1 {
|
||||||
t.Fatalf("Expecting to get one conflict but got %v", err)
|
t.Fatalf("Expecting to get one conflict but got %v", err)
|
||||||
@ -125,7 +134,7 @@ func TestUpdateBeforeFirstApply(t *testing.T) {
|
|||||||
t.Fatalf("Expecting conflict message to contain %q but got %q: %v", e, a, err)
|
t.Fatalf("Expecting conflict message to contain %q but got %q: %v", e, a, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := f.Apply(appliedBytes, "fieldmanager_test_apply", true); err != nil {
|
if err := f.Apply(appliedObj, "fieldmanager_test_apply", true); err != nil {
|
||||||
t.Fatalf("failed to update object: %v", err)
|
t.Fatalf("failed to update object: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,8 +64,8 @@ func (f *stripMetaManager) Update(liveObj, newObj runtime.Object, managed Manage
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Manager.
|
// Apply implements Manager.
|
||||||
func (f *stripMetaManager) Apply(liveObj runtime.Object, patch []byte, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
func (f *stripMetaManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
||||||
newObj, managed, err := f.fieldManager.Apply(liveObj, patch, managed, manager, force)
|
newObj, managed, err := f.fieldManager.Apply(liveObj, appliedObj, managed, manager, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal"
|
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal"
|
||||||
@ -30,7 +30,6 @@ import (
|
|||||||
openapiproto "k8s.io/kube-openapi/pkg/util/proto"
|
openapiproto "k8s.io/kube-openapi/pkg/util/proto"
|
||||||
"sigs.k8s.io/structured-merge-diff/fieldpath"
|
"sigs.k8s.io/structured-merge-diff/fieldpath"
|
||||||
"sigs.k8s.io/structured-merge-diff/merge"
|
"sigs.k8s.io/structured-merge-diff/merge"
|
||||||
"sigs.k8s.io/yaml"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type structuredMergeManager struct {
|
type structuredMergeManager struct {
|
||||||
@ -136,22 +135,21 @@ func (f *structuredMergeManager) Update(liveObj, newObj runtime.Object, managed
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply implements Manager.
|
// Apply implements Manager.
|
||||||
func (f *structuredMergeManager) Apply(liveObj runtime.Object, patch []byte, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
func (f *structuredMergeManager) Apply(liveObj, patchObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
||||||
patchObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
|
||||||
if err := yaml.Unmarshal(patch, &patchObj.Object); err != nil {
|
|
||||||
return nil, nil, errors.NewBadRequest(fmt.Sprintf("error decoding YAML: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the patch object has the same version as the live object
|
// Check that the patch object has the same version as the live object
|
||||||
if patchObj.GetAPIVersion() != f.groupVersion.String() {
|
if patchVersion := patchObj.GetObjectKind().GroupVersionKind().GroupVersion(); patchVersion != f.groupVersion {
|
||||||
return nil, nil,
|
return nil, nil,
|
||||||
errors.NewBadRequest(
|
errors.NewBadRequest(
|
||||||
fmt.Sprintf("Incorrect version specified in apply patch. "+
|
fmt.Sprintf("Incorrect version specified in apply patch. "+
|
||||||
"Specified patch version: %s, expected: %s",
|
"Specified patch version: %s, expected: %s",
|
||||||
patchObj.GetAPIVersion(), f.groupVersion.String()))
|
patchVersion, f.groupVersion))
|
||||||
}
|
}
|
||||||
|
|
||||||
if patchObj.GetManagedFields() != nil {
|
patchObjMeta, err := meta.Accessor(patchObj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("couldn't get accessor: %v", err)
|
||||||
|
}
|
||||||
|
if patchObjMeta.GetManagedFields() != nil {
|
||||||
return nil, nil, errors.NewBadRequest(fmt.Sprintf("metadata.managedFields must be nil"))
|
return nil, nil, errors.NewBadRequest(fmt.Sprintf("metadata.managedFields must be nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme"
|
metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@ -48,6 +49,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/util/dryrun"
|
"k8s.io/apiserver/pkg/util/dryrun"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
utiltrace "k8s.io/utils/trace"
|
utiltrace "k8s.io/utils/trace"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -433,7 +435,13 @@ func (p *applyPatcher) applyPatchToCurrentObject(obj runtime.Object) (runtime.Ob
|
|||||||
if p.fieldManager == nil {
|
if p.fieldManager == nil {
|
||||||
panic("FieldManager must be installed to run apply")
|
panic("FieldManager must be installed to run apply")
|
||||||
}
|
}
|
||||||
return p.fieldManager.Apply(obj, p.patch, p.options.FieldManager, force)
|
|
||||||
|
patchObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
if err := yaml.Unmarshal(p.patch, &patchObj.Object); err != nil {
|
||||||
|
return nil, errors.NewBadRequest(fmt.Sprintf("error decoding YAML: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.fieldManager.Apply(obj, patchObj, p.options.FieldManager, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *applyPatcher) createNewObject() (runtime.Object, error) {
|
func (p *applyPatcher) createNewObject() (runtime.Object, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user