strip selected fields from managedFields

refactor fieldstrip and update tests

add checks and remove empty fields

shorten test and check for nil manager

fix gofmt

panic on nil manager
This commit is contained in:
Kevin Wiesmüller 2019-02-03 22:22:10 +01:00
parent f7c4389b79
commit 9082cac482
2 changed files with 93 additions and 4 deletions

View File

@ -51,6 +51,7 @@ func NewFieldManager(models openapiproto.Models, objectConverter runtime.ObjectC
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &FieldManager{ return &FieldManager{
typeConverter: typeConverter, typeConverter: typeConverter,
objectConverter: objectConverter, objectConverter: objectConverter,
@ -130,6 +131,7 @@ func (f *FieldManager) Update(liveObj, newObj runtime.Object, manager string) (r
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to update ManagedFields: %v", err) return nil, fmt.Errorf("failed to update ManagedFields: %v", err)
} }
managed = f.stripFields(managed, manager)
if err := internal.EncodeObjectManagedFields(newObj, managed); err != nil { if err := internal.EncodeObjectManagedFields(newObj, managed); err != nil {
return nil, fmt.Errorf("failed to encode managed fields: %v", err) return nil, fmt.Errorf("failed to encode managed fields: %v", err)
@ -180,6 +182,7 @@ func (f *FieldManager) Apply(liveObj runtime.Object, patch []byte, force bool) (
} }
return nil, err return nil, err
} }
managed = f.stripFields(managed, manager)
newObj, err := f.typeConverter.TypedToObject(newObjTyped) newObj, err := f.typeConverter.TypedToObject(newObjTyped)
if err != nil { if err != nil {
@ -223,3 +226,31 @@ func (f *FieldManager) buildManagerInfo(prefix string, operation metav1.ManagedF
} }
return internal.BuildManagerIdentifier(&managerInfo) return internal.BuildManagerIdentifier(&managerInfo)
} }
// stripSet is the list of fields that should never be part of a mangedFields.
var stripSet = fieldpath.NewSet(
fieldpath.MakePathOrDie("apiVersion"),
fieldpath.MakePathOrDie("kind"),
fieldpath.MakePathOrDie("metadata", "name"),
fieldpath.MakePathOrDie("metadata", "namespace"),
fieldpath.MakePathOrDie("metadata", "creationTimestamp"),
fieldpath.MakePathOrDie("metadata", "selfLink"),
fieldpath.MakePathOrDie("metadata", "uid"),
fieldpath.MakePathOrDie("metadata", "resourceVersion"),
)
// stripFields removes a predefined set of paths found in typed from managed and returns the updated ManagedFields
func (f *FieldManager) stripFields(managed fieldpath.ManagedFields, manager string) fieldpath.ManagedFields {
vs, ok := managed[manager]
if ok {
if vs == nil {
panic(fmt.Sprintf("Found unexpected nil manager which should never happen: %s", manager))
}
vs.Set = vs.Set.Difference(stripSet)
if vs.Set.Empty() {
delete(managed, manager)
}
}
return managed
}

View File

@ -223,7 +223,11 @@ func TestApplyManagedFields(t *testing.T) {
"apiVersion": "v1", "apiVersion": "v1",
"kind": "ConfigMap", "kind": "ConfigMap",
"metadata": { "metadata": {
"name": "test-cm" "name": "test-cm",
"namespace": "default",
"labels": {
"test-label": "test"
}
}, },
"data": { "data": {
"key": "value" "key": "value"
@ -267,16 +271,19 @@ func TestApplyManagedFields(t *testing.T) {
"uid": "` + string(accessor.GetUID()) + `", "uid": "` + string(accessor.GetUID()) + `",
"resourceVersion": "` + accessor.GetResourceVersion() + `", "resourceVersion": "` + accessor.GetResourceVersion() + `",
"creationTimestamp": "` + accessor.GetCreationTimestamp().UTC().Format(time.RFC3339) + `", "creationTimestamp": "` + accessor.GetCreationTimestamp().UTC().Format(time.RFC3339) + `",
"labels": {
"test-label": "test"
},
"managedFields": [ "managedFields": [
{ {
"manager": "apply", "manager": "apply",
"operation": "Apply", "operation": "Apply",
"apiVersion": "v1", "apiVersion": "v1",
"fields": { "fields": {
"f:apiVersion": {},
"f:kind": {},
"f:metadata": { "f:metadata": {
"f:name": {} "f:labels": {
"f:test-label": {}
}
} }
} }
}, },
@ -302,3 +309,54 @@ func TestApplyManagedFields(t *testing.T) {
t.Fatalf("Expected:\n%v\nGot:\n%v", string(expected), string(actual)) t.Fatalf("Expected:\n%v\nGot:\n%v", string(expected), string(actual))
} }
} }
// TestApplyRemovesEmptyManagedFields there are no empty managers in managedFields
func TestApplyRemovesEmptyManagedFields(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, true)()
_, client, closeFn := setup(t)
defer closeFn()
obj := []byte(`{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {
"name": "test-cm",
"namespace": "default"
}
}`)
_, err := client.CoreV1().RESTClient().Patch(types.ApplyPatchType).
Namespace("default").
Resource("configmaps").
Name("test-cm").
Body(obj).
Do().
Get()
if err != nil {
t.Fatalf("Failed to create object using Apply patch: %v", err)
}
_, err = client.CoreV1().RESTClient().Patch(types.ApplyPatchType).
Namespace("default").
Resource("configmaps").
Name("test-cm").
Body(obj).Do().Get()
if err != nil {
t.Fatalf("Failed to patch object: %v", err)
}
object, err := client.CoreV1().RESTClient().Get().Namespace("default").Resource("configmaps").Name("test-cm").Do().Get()
if err != nil {
t.Fatalf("Failed to retrieve object: %v", err)
}
accessor, err := meta.Accessor(object)
if err != nil {
t.Fatalf("Failed to get meta accessor: %v", err)
}
if managed := accessor.GetManagedFields(); managed != nil {
t.Fatalf("Object contains unexpected managedFields: %v", managed)
}
}