...

Source file src/k8s.io/apimachinery/pkg/util/managedfields/internal/managedfields.go

Documentation: k8s.io/apimachinery/pkg/util/managedfields/internal

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package internal
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"sort"
    23  
    24  	"k8s.io/apimachinery/pkg/api/meta"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
    28  )
    29  
    30  // ManagedInterface groups a fieldpath.ManagedFields together with the timestamps associated with each operation.
    31  type ManagedInterface interface {
    32  	// Fields gets the fieldpath.ManagedFields.
    33  	Fields() fieldpath.ManagedFields
    34  
    35  	// Times gets the timestamps associated with each operation.
    36  	Times() map[string]*metav1.Time
    37  }
    38  
    39  type managedStruct struct {
    40  	fields fieldpath.ManagedFields
    41  	times  map[string]*metav1.Time
    42  }
    43  
    44  var _ ManagedInterface = &managedStruct{}
    45  
    46  // Fields implements ManagedInterface.
    47  func (m *managedStruct) Fields() fieldpath.ManagedFields {
    48  	return m.fields
    49  }
    50  
    51  // Times implements ManagedInterface.
    52  func (m *managedStruct) Times() map[string]*metav1.Time {
    53  	return m.times
    54  }
    55  
    56  // NewEmptyManaged creates an empty ManagedInterface.
    57  func NewEmptyManaged() ManagedInterface {
    58  	return NewManaged(fieldpath.ManagedFields{}, map[string]*metav1.Time{})
    59  }
    60  
    61  // NewManaged creates a ManagedInterface from a fieldpath.ManagedFields and the timestamps associated with each operation.
    62  func NewManaged(f fieldpath.ManagedFields, t map[string]*metav1.Time) ManagedInterface {
    63  	return &managedStruct{
    64  		fields: f,
    65  		times:  t,
    66  	}
    67  }
    68  
    69  // RemoveObjectManagedFields removes the ManagedFields from the object
    70  // before we merge so that it doesn't appear in the ManagedFields
    71  // recursively.
    72  func RemoveObjectManagedFields(obj runtime.Object) {
    73  	accessor, err := meta.Accessor(obj)
    74  	if err != nil {
    75  		panic(fmt.Sprintf("couldn't get accessor: %v", err))
    76  	}
    77  	accessor.SetManagedFields(nil)
    78  }
    79  
    80  // EncodeObjectManagedFields converts and stores the fieldpathManagedFields into the objects ManagedFields
    81  func EncodeObjectManagedFields(obj runtime.Object, managed ManagedInterface) error {
    82  	accessor, err := meta.Accessor(obj)
    83  	if err != nil {
    84  		panic(fmt.Sprintf("couldn't get accessor: %v", err))
    85  	}
    86  
    87  	encodedManagedFields, err := encodeManagedFields(managed)
    88  	if err != nil {
    89  		return fmt.Errorf("failed to convert back managed fields to API: %v", err)
    90  	}
    91  	accessor.SetManagedFields(encodedManagedFields)
    92  
    93  	return nil
    94  }
    95  
    96  // DecodeManagedFields converts ManagedFields from the wire format (api format)
    97  // to the format used by sigs.k8s.io/structured-merge-diff
    98  func DecodeManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (ManagedInterface, error) {
    99  	managed := managedStruct{}
   100  	managed.fields = make(fieldpath.ManagedFields, len(encodedManagedFields))
   101  	managed.times = make(map[string]*metav1.Time, len(encodedManagedFields))
   102  
   103  	for i, encodedVersionedSet := range encodedManagedFields {
   104  		switch encodedVersionedSet.Operation {
   105  		case metav1.ManagedFieldsOperationApply, metav1.ManagedFieldsOperationUpdate:
   106  		default:
   107  			return nil, fmt.Errorf("operation must be `Apply` or `Update`")
   108  		}
   109  		if len(encodedVersionedSet.APIVersion) < 1 {
   110  			return nil, fmt.Errorf("apiVersion must not be empty")
   111  		}
   112  		switch encodedVersionedSet.FieldsType {
   113  		case "FieldsV1":
   114  			// Valid case.
   115  		case "":
   116  			return nil, fmt.Errorf("missing fieldsType in managed fields entry %d", i)
   117  		default:
   118  			return nil, fmt.Errorf("invalid fieldsType %q in managed fields entry %d", encodedVersionedSet.FieldsType, i)
   119  		}
   120  		manager, err := BuildManagerIdentifier(&encodedVersionedSet)
   121  		if err != nil {
   122  			return nil, fmt.Errorf("error decoding manager from %v: %v", encodedVersionedSet, err)
   123  		}
   124  		managed.fields[manager], err = decodeVersionedSet(&encodedVersionedSet)
   125  		if err != nil {
   126  			return nil, fmt.Errorf("error decoding versioned set from %v: %v", encodedVersionedSet, err)
   127  		}
   128  		managed.times[manager] = encodedVersionedSet.Time
   129  	}
   130  	return &managed, nil
   131  }
   132  
   133  // BuildManagerIdentifier creates a manager identifier string from a ManagedFieldsEntry
   134  func BuildManagerIdentifier(encodedManager *metav1.ManagedFieldsEntry) (manager string, err error) {
   135  	encodedManagerCopy := *encodedManager
   136  
   137  	// Never include fields type in the manager identifier
   138  	encodedManagerCopy.FieldsType = ""
   139  
   140  	// Never include the fields in the manager identifier
   141  	encodedManagerCopy.FieldsV1 = nil
   142  
   143  	// Never include the time in the manager identifier
   144  	encodedManagerCopy.Time = nil
   145  
   146  	// For appliers, don't include the APIVersion in the manager identifier,
   147  	// so it will always have the same manager identifier each time it applied.
   148  	if encodedManager.Operation == metav1.ManagedFieldsOperationApply {
   149  		encodedManagerCopy.APIVersion = ""
   150  	}
   151  
   152  	// Use the remaining fields to build the manager identifier
   153  	b, err := json.Marshal(&encodedManagerCopy)
   154  	if err != nil {
   155  		return "", fmt.Errorf("error marshalling manager identifier: %v", err)
   156  	}
   157  
   158  	return string(b), nil
   159  }
   160  
   161  func decodeVersionedSet(encodedVersionedSet *metav1.ManagedFieldsEntry) (versionedSet fieldpath.VersionedSet, err error) {
   162  	fields := EmptyFields
   163  	if encodedVersionedSet.FieldsV1 != nil {
   164  		fields = *encodedVersionedSet.FieldsV1
   165  	}
   166  	set, err := FieldsToSet(fields)
   167  	if err != nil {
   168  		return nil, fmt.Errorf("error decoding set: %v", err)
   169  	}
   170  	return fieldpath.NewVersionedSet(&set, fieldpath.APIVersion(encodedVersionedSet.APIVersion), encodedVersionedSet.Operation == metav1.ManagedFieldsOperationApply), nil
   171  }
   172  
   173  // encodeManagedFields converts ManagedFields from the format used by
   174  // sigs.k8s.io/structured-merge-diff to the wire format (api format)
   175  func encodeManagedFields(managed ManagedInterface) (encodedManagedFields []metav1.ManagedFieldsEntry, err error) {
   176  	if len(managed.Fields()) == 0 {
   177  		return nil, nil
   178  	}
   179  	encodedManagedFields = []metav1.ManagedFieldsEntry{}
   180  	for manager := range managed.Fields() {
   181  		versionedSet := managed.Fields()[manager]
   182  		v, err := encodeManagerVersionedSet(manager, versionedSet)
   183  		if err != nil {
   184  			return nil, fmt.Errorf("error encoding versioned set for %v: %v", manager, err)
   185  		}
   186  		if t, ok := managed.Times()[manager]; ok {
   187  			v.Time = t
   188  		}
   189  		encodedManagedFields = append(encodedManagedFields, *v)
   190  	}
   191  	return sortEncodedManagedFields(encodedManagedFields)
   192  }
   193  
   194  func sortEncodedManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (sortedManagedFields []metav1.ManagedFieldsEntry, err error) {
   195  	sort.Slice(encodedManagedFields, func(i, j int) bool {
   196  		p, q := encodedManagedFields[i], encodedManagedFields[j]
   197  
   198  		if p.Operation != q.Operation {
   199  			return p.Operation < q.Operation
   200  		}
   201  
   202  		pSeconds, qSeconds := int64(0), int64(0)
   203  		if p.Time != nil {
   204  			pSeconds = p.Time.Unix()
   205  		}
   206  		if q.Time != nil {
   207  			qSeconds = q.Time.Unix()
   208  		}
   209  		if pSeconds != qSeconds {
   210  			return pSeconds < qSeconds
   211  		}
   212  
   213  		if p.Manager != q.Manager {
   214  			return p.Manager < q.Manager
   215  		}
   216  
   217  		if p.APIVersion != q.APIVersion {
   218  			return p.APIVersion < q.APIVersion
   219  		}
   220  		return p.Subresource < q.Subresource
   221  	})
   222  
   223  	return encodedManagedFields, nil
   224  }
   225  
   226  func encodeManagerVersionedSet(manager string, versionedSet fieldpath.VersionedSet) (encodedVersionedSet *metav1.ManagedFieldsEntry, err error) {
   227  	encodedVersionedSet = &metav1.ManagedFieldsEntry{}
   228  
   229  	// Get as many fields as we can from the manager identifier
   230  	err = json.Unmarshal([]byte(manager), encodedVersionedSet)
   231  	if err != nil {
   232  		return nil, fmt.Errorf("error unmarshalling manager identifier %v: %v", manager, err)
   233  	}
   234  
   235  	// Get the APIVersion, Operation, and Fields from the VersionedSet
   236  	encodedVersionedSet.APIVersion = string(versionedSet.APIVersion())
   237  	if versionedSet.Applied() {
   238  		encodedVersionedSet.Operation = metav1.ManagedFieldsOperationApply
   239  	}
   240  	encodedVersionedSet.FieldsType = "FieldsV1"
   241  	fields, err := SetToFields(*versionedSet.Set())
   242  	if err != nil {
   243  		return nil, fmt.Errorf("error encoding set: %v", err)
   244  	}
   245  	encodedVersionedSet.FieldsV1 = &fields
   246  
   247  	return encodedVersionedSet, nil
   248  }
   249  

View as plain text