Merge pull request #81524 from jennybuckley/apply-group-updates-by-manager
Group managedFieldsEntries for update by manager name Kubernetes-commit: 6f13032fb445f4d4c501bd236eef22f8836edb7a
This commit is contained in:
commit
33bf53f7c4
|
@ -440,7 +440,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/apimachinery",
|
||||
"Rev": "21ddcbbef9e1"
|
||||
"Rev": "ac02f8882ef6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/client-go",
|
||||
|
|
4
go.mod
4
go.mod
|
@ -53,7 +53,7 @@ require (
|
|||
gopkg.in/yaml.v2 v2.2.2
|
||||
gotest.tools v2.2.0+incompatible // indirect
|
||||
k8s.io/api v0.0.0-20190820101039-d651a1528133
|
||||
k8s.io/apimachinery v0.0.0-20190820100750-21ddcbbef9e1
|
||||
k8s.io/apimachinery v0.0.0-20190820100751-ac02f8882ef6
|
||||
k8s.io/client-go v0.0.0-20190820101407-c8dc69f8a8bf
|
||||
k8s.io/component-base v0.0.0-20190820102445-1391c9d535ae
|
||||
k8s.io/klog v0.4.0
|
||||
|
@ -69,7 +69,7 @@ replace (
|
|||
golang.org/x/sys => golang.org/x/sys v0.0.0-20190209173611-3b5209105503
|
||||
golang.org/x/text => golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db
|
||||
k8s.io/api => k8s.io/api v0.0.0-20190820101039-d651a1528133
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190820100750-21ddcbbef9e1
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190820100751-ac02f8882ef6
|
||||
k8s.io/client-go => k8s.io/client-go v0.0.0-20190820101407-c8dc69f8a8bf
|
||||
k8s.io/component-base => k8s.io/component-base v0.0.0-20190820102445-1391c9d535ae
|
||||
)
|
||||
|
|
2
go.sum
2
go.sum
|
@ -244,7 +244,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
k8s.io/api v0.0.0-20190820101039-d651a1528133/go.mod h1:AlhL1I0Xqh5Tyz0HsxjEhy+iKci9l1Qy3UMDFW7iG3A=
|
||||
k8s.io/apimachinery v0.0.0-20190820100750-21ddcbbef9e1/go.mod h1:EZoIMuAgG/4v58YL+bz0kqnivqupk28fKYxFCa5e6X8=
|
||||
k8s.io/apimachinery v0.0.0-20190820100751-ac02f8882ef6/go.mod h1:EZoIMuAgG/4v58YL+bz0kqnivqupk28fKYxFCa5e6X8=
|
||||
k8s.io/client-go v0.0.0-20190820101407-c8dc69f8a8bf/go.mod h1:/Fq6Zm28c3mTL4uNB5Blb9K7ufxovl3zPT6sCLZLrkE=
|
||||
k8s.io/component-base v0.0.0-20190820102445-1391c9d535ae/go.mod h1:1+cN3+FO5lQOzpBhBsFmxSIJpCAcD9kEEZnUIaKuOGE=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
|
|
|
@ -98,7 +98,7 @@ func (f *FieldManager) Update(liveObj, newObj runtime.Object, manager string) (r
|
|||
// If the managed field is empty or we failed to decode it,
|
||||
// let's try the live object. This is to prevent clients who
|
||||
// don't understand managedFields from deleting it accidentally.
|
||||
if err != nil || len(managed) == 0 {
|
||||
if err != nil || len(managed.Fields) == 0 {
|
||||
managed, err = internal.DecodeObjectManagedFields(liveObj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode managed fields: %v", err)
|
||||
|
@ -133,11 +133,14 @@ func (f *FieldManager) Update(liveObj, newObj runtime.Object, manager string) (r
|
|||
}
|
||||
|
||||
// TODO(apelisse) use the first return value when unions are implemented
|
||||
_, managed, err = f.updater.Update(liveObjTyped, newObjTyped, apiVersion, managed, manager)
|
||||
_, managed.Fields, err = f.updater.Update(liveObjTyped, newObjTyped, apiVersion, managed.Fields, manager)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update ManagedFields: %v", err)
|
||||
}
|
||||
managed = f.stripFields(managed, manager)
|
||||
managed.Fields = f.stripFields(managed.Fields, manager)
|
||||
|
||||
// Update the time in the managedFieldsEntry for this operation
|
||||
managed.Times[manager] = &metav1.Time{Time: time.Now().UTC()}
|
||||
|
||||
if err := internal.EncodeObjectManagedFields(newObj, managed); err != nil {
|
||||
return nil, fmt.Errorf("failed to encode managed fields: %v", err)
|
||||
|
@ -192,14 +195,17 @@ func (f *FieldManager) Apply(liveObj runtime.Object, patch []byte, fieldManager
|
|||
}
|
||||
|
||||
apiVersion := fieldpath.APIVersion(f.groupVersion.String())
|
||||
newObjTyped, managed, err := f.updater.Apply(liveObjTyped, patchObjTyped, apiVersion, managed, manager, force)
|
||||
newObjTyped, managedFields, err := f.updater.Apply(liveObjTyped, patchObjTyped, apiVersion, managed.Fields, manager, force)
|
||||
if err != nil {
|
||||
if conflicts, ok := err.(merge.Conflicts); ok {
|
||||
return nil, internal.NewConflictError(conflicts)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
managed = f.stripFields(managed, manager)
|
||||
managed.Fields = f.stripFields(managedFields, manager)
|
||||
|
||||
// Update the time in the managedFieldsEntry for this operation
|
||||
managed.Times[manager] = &metav1.Time{Time: time.Now().UTC()}
|
||||
|
||||
newObj, err := f.typeConverter.TypedToObject(newObjTyped)
|
||||
if err != nil {
|
||||
|
@ -236,7 +242,6 @@ func (f *FieldManager) buildManagerInfo(prefix string, operation metav1.ManagedF
|
|||
Manager: prefix,
|
||||
Operation: operation,
|
||||
APIVersion: f.groupVersion.String(),
|
||||
Time: &metav1.Time{Time: time.Now().UTC()},
|
||||
}
|
||||
if managerInfo.Manager == "" {
|
||||
managerInfo.Manager = "unknown"
|
||||
|
|
|
@ -28,6 +28,12 @@ import (
|
|||
"sigs.k8s.io/structured-merge-diff/fieldpath"
|
||||
)
|
||||
|
||||
// Managed groups a fieldpath.ManagedFields together with the timestamps associated with each operation.
|
||||
type Managed struct {
|
||||
Fields fieldpath.ManagedFields
|
||||
Times map[string]*metav1.Time
|
||||
}
|
||||
|
||||
// RemoveObjectManagedFields removes the ManagedFields from the object
|
||||
// before we merge so that it doesn't appear in the ManagedFields
|
||||
// recursively.
|
||||
|
@ -40,9 +46,9 @@ func RemoveObjectManagedFields(obj runtime.Object) {
|
|||
}
|
||||
|
||||
// DecodeObjectManagedFields extracts and converts the objects ManagedFields into a fieldpath.ManagedFields.
|
||||
func DecodeObjectManagedFields(from runtime.Object) (fieldpath.ManagedFields, error) {
|
||||
func DecodeObjectManagedFields(from runtime.Object) (Managed, error) {
|
||||
if from == nil {
|
||||
return fieldpath.ManagedFields{}, nil
|
||||
return Managed{}, nil
|
||||
}
|
||||
accessor, err := meta.Accessor(from)
|
||||
if err != nil {
|
||||
|
@ -51,42 +57,44 @@ func DecodeObjectManagedFields(from runtime.Object) (fieldpath.ManagedFields, er
|
|||
|
||||
managed, err := decodeManagedFields(accessor.GetManagedFields())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert managed fields from API: %v", err)
|
||||
return Managed{}, fmt.Errorf("failed to convert managed fields from API: %v", err)
|
||||
}
|
||||
return managed, err
|
||||
}
|
||||
|
||||
// EncodeObjectManagedFields converts and stores the fieldpathManagedFields into the objects ManagedFields
|
||||
func EncodeObjectManagedFields(obj runtime.Object, fields fieldpath.ManagedFields) error {
|
||||
func EncodeObjectManagedFields(obj runtime.Object, managed Managed) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("couldn't get accessor: %v", err))
|
||||
}
|
||||
|
||||
managed, err := encodeManagedFields(fields)
|
||||
encodedManagedFields, err := encodeManagedFields(managed)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert back managed fields to API: %v", err)
|
||||
}
|
||||
accessor.SetManagedFields(managed)
|
||||
accessor.SetManagedFields(encodedManagedFields)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// decodeManagedFields converts ManagedFields from the wire format (api format)
|
||||
// to the format used by sigs.k8s.io/structured-merge-diff
|
||||
func decodeManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (managedFields fieldpath.ManagedFields, err error) {
|
||||
managedFields = make(fieldpath.ManagedFields, len(encodedManagedFields))
|
||||
func decodeManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (managed Managed, err error) {
|
||||
managed.Fields = make(fieldpath.ManagedFields, len(encodedManagedFields))
|
||||
managed.Times = make(map[string]*metav1.Time, len(encodedManagedFields))
|
||||
for _, encodedVersionedSet := range encodedManagedFields {
|
||||
manager, err := BuildManagerIdentifier(&encodedVersionedSet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding manager from %v: %v", encodedVersionedSet, err)
|
||||
return Managed{}, fmt.Errorf("error decoding manager from %v: %v", encodedVersionedSet, err)
|
||||
}
|
||||
managedFields[manager], err = decodeVersionedSet(&encodedVersionedSet)
|
||||
managed.Fields[manager], err = decodeVersionedSet(&encodedVersionedSet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding versioned set from %v: %v", encodedVersionedSet, err)
|
||||
return Managed{}, fmt.Errorf("error decoding versioned set from %v: %v", encodedVersionedSet, err)
|
||||
}
|
||||
managed.Times[manager] = encodedVersionedSet.Time
|
||||
}
|
||||
return managedFields, nil
|
||||
return managed, nil
|
||||
}
|
||||
|
||||
// BuildManagerIdentifier creates a manager identifier string from a ManagedFieldsEntry
|
||||
|
@ -96,11 +104,13 @@ func BuildManagerIdentifier(encodedManager *metav1.ManagedFieldsEntry) (manager
|
|||
// Never include the fields in the manager identifier
|
||||
encodedManagerCopy.Fields = nil
|
||||
|
||||
// For appliers, don't include the APIVersion or Time in the manager identifier,
|
||||
// Never include the time in the manager identifier
|
||||
encodedManagerCopy.Time = nil
|
||||
|
||||
// For appliers, don't include the APIVersion in the manager identifier,
|
||||
// so it will always have the same manager identifier each time it applied.
|
||||
if encodedManager.Operation == metav1.ManagedFieldsOperationApply {
|
||||
encodedManagerCopy.APIVersion = ""
|
||||
encodedManagerCopy.Time = nil
|
||||
}
|
||||
|
||||
// Use the remaining fields to build the manager identifier
|
||||
|
@ -126,21 +136,17 @@ func decodeVersionedSet(encodedVersionedSet *metav1.ManagedFieldsEntry) (version
|
|||
|
||||
// encodeManagedFields converts ManagedFields from the format used by
|
||||
// sigs.k8s.io/structured-merge-diff to the wire format (api format)
|
||||
func encodeManagedFields(managedFields fieldpath.ManagedFields) (encodedManagedFields []metav1.ManagedFieldsEntry, err error) {
|
||||
// Sort the keys so a predictable order will be used.
|
||||
managers := []string{}
|
||||
for manager := range managedFields {
|
||||
managers = append(managers, manager)
|
||||
}
|
||||
sort.Strings(managers)
|
||||
|
||||
func encodeManagedFields(managed Managed) (encodedManagedFields []metav1.ManagedFieldsEntry, err error) {
|
||||
encodedManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
for _, manager := range managers {
|
||||
versionedSet := managedFields[manager]
|
||||
for manager := range managed.Fields {
|
||||
versionedSet := managed.Fields[manager]
|
||||
v, err := encodeManagerVersionedSet(manager, versionedSet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error encoding versioned set for %v: %v", manager, err)
|
||||
}
|
||||
if t, ok := managed.Times[manager]; ok {
|
||||
v.Time = t
|
||||
}
|
||||
encodedManagedFields = append(encodedManagedFields, *v)
|
||||
}
|
||||
return sortEncodedManagedFields(encodedManagedFields)
|
||||
|
|
|
@ -169,7 +169,7 @@ manager: foo
|
|||
operation: Update
|
||||
time: "2001-02-03T04:05:06Z"
|
||||
`,
|
||||
expected: "{\"manager\":\"foo\",\"operation\":\"Update\",\"apiVersion\":\"v1\",\"time\":\"2001-02-03T04:05:06Z\"}",
|
||||
expected: "{\"manager\":\"foo\",\"operation\":\"Update\",\"apiVersion\":\"v1\"}",
|
||||
},
|
||||
{
|
||||
managedFieldsEntry: `
|
||||
|
|
Loading…
Reference in New Issue