...

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

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

     1  /*
     2  Copyright 2019 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  	"fmt"
    21  
    22  	"k8s.io/apimachinery/pkg/api/errors"
    23  	"k8s.io/apimachinery/pkg/api/meta"
    24  	"k8s.io/apimachinery/pkg/runtime"
    25  	"k8s.io/apimachinery/pkg/runtime/schema"
    26  	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
    27  	"sigs.k8s.io/structured-merge-diff/v4/merge"
    28  	"sigs.k8s.io/structured-merge-diff/v4/typed"
    29  )
    30  
    31  type structuredMergeManager struct {
    32  	typeConverter   TypeConverter
    33  	objectConverter runtime.ObjectConvertor
    34  	objectDefaulter runtime.ObjectDefaulter
    35  	groupVersion    schema.GroupVersion
    36  	hubVersion      schema.GroupVersion
    37  	updater         merge.Updater
    38  }
    39  
    40  var _ Manager = &structuredMergeManager{}
    41  
    42  // NewStructuredMergeManager creates a new Manager that merges apply requests
    43  // and update managed fields for other types of requests.
    44  func NewStructuredMergeManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion, resetFields map[fieldpath.APIVersion]*fieldpath.Set) (Manager, error) {
    45  	if typeConverter == nil {
    46  		return nil, fmt.Errorf("typeconverter must not be nil")
    47  	}
    48  	return &structuredMergeManager{
    49  		typeConverter:   typeConverter,
    50  		objectConverter: objectConverter,
    51  		objectDefaulter: objectDefaulter,
    52  		groupVersion:    gv,
    53  		hubVersion:      hub,
    54  		updater: merge.Updater{
    55  			Converter:     newVersionConverter(typeConverter, objectConverter, hub), // This is the converter provided to SMD from k8s
    56  			IgnoredFields: resetFields,
    57  		},
    58  	}, nil
    59  }
    60  
    61  // NewCRDStructuredMergeManager creates a new Manager specifically for
    62  // CRDs. This allows for the possibility of fields which are not defined
    63  // in models, as well as having no models defined at all.
    64  func NewCRDStructuredMergeManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion, resetFields map[fieldpath.APIVersion]*fieldpath.Set) (_ Manager, err error) {
    65  	return &structuredMergeManager{
    66  		typeConverter:   typeConverter,
    67  		objectConverter: objectConverter,
    68  		objectDefaulter: objectDefaulter,
    69  		groupVersion:    gv,
    70  		hubVersion:      hub,
    71  		updater: merge.Updater{
    72  			Converter:     newCRDVersionConverter(typeConverter, objectConverter, hub),
    73  			IgnoredFields: resetFields,
    74  		},
    75  	}, nil
    76  }
    77  
    78  func objectGVKNN(obj runtime.Object) string {
    79  	name := "<unknown>"
    80  	namespace := "<unknown>"
    81  	if accessor, err := meta.Accessor(obj); err == nil {
    82  		name = accessor.GetName()
    83  		namespace = accessor.GetNamespace()
    84  	}
    85  
    86  	return fmt.Sprintf("%v/%v; %v", namespace, name, obj.GetObjectKind().GroupVersionKind())
    87  }
    88  
    89  // Update implements Manager.
    90  func (f *structuredMergeManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
    91  	newObjVersioned, err := f.toVersioned(newObj)
    92  	if err != nil {
    93  		return nil, nil, fmt.Errorf("failed to convert new object (%v) to proper version (%v): %v", objectGVKNN(newObj), f.groupVersion, err)
    94  	}
    95  	liveObjVersioned, err := f.toVersioned(liveObj)
    96  	if err != nil {
    97  		return nil, nil, fmt.Errorf("failed to convert live object (%v) to proper version: %v", objectGVKNN(liveObj), err)
    98  	}
    99  	newObjTyped, err := f.typeConverter.ObjectToTyped(newObjVersioned, typed.AllowDuplicates)
   100  	if err != nil {
   101  		return nil, nil, fmt.Errorf("failed to convert new object (%v) to smd typed: %v", objectGVKNN(newObjVersioned), err)
   102  	}
   103  	liveObjTyped, err := f.typeConverter.ObjectToTyped(liveObjVersioned, typed.AllowDuplicates)
   104  	if err != nil {
   105  		return nil, nil, fmt.Errorf("failed to convert live object (%v) to smd typed: %v", objectGVKNN(liveObjVersioned), err)
   106  	}
   107  	apiVersion := fieldpath.APIVersion(f.groupVersion.String())
   108  
   109  	// TODO(apelisse) use the first return value when unions are implemented
   110  	_, managedFields, err := f.updater.Update(liveObjTyped, newObjTyped, apiVersion, managed.Fields(), manager)
   111  	if err != nil {
   112  		return nil, nil, fmt.Errorf("failed to update ManagedFields (%v): %v", objectGVKNN(newObjVersioned), err)
   113  	}
   114  	managed = NewManaged(managedFields, managed.Times())
   115  
   116  	return newObj, managed, nil
   117  }
   118  
   119  // Apply implements Manager.
   120  func (f *structuredMergeManager) Apply(liveObj, patchObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
   121  	// Check that the patch object has the same version as the live object
   122  	if patchVersion := patchObj.GetObjectKind().GroupVersionKind().GroupVersion(); patchVersion != f.groupVersion {
   123  		return nil, nil,
   124  			errors.NewBadRequest(
   125  				fmt.Sprintf("Incorrect version specified in apply patch. "+
   126  					"Specified patch version: %s, expected: %s",
   127  					patchVersion, f.groupVersion))
   128  	}
   129  
   130  	patchObjMeta, err := meta.Accessor(patchObj)
   131  	if err != nil {
   132  		return nil, nil, fmt.Errorf("couldn't get accessor: %v", err)
   133  	}
   134  	if patchObjMeta.GetManagedFields() != nil {
   135  		return nil, nil, errors.NewBadRequest("metadata.managedFields must be nil")
   136  	}
   137  
   138  	liveObjVersioned, err := f.toVersioned(liveObj)
   139  	if err != nil {
   140  		return nil, nil, fmt.Errorf("failed to convert live object (%v) to proper version: %v", objectGVKNN(liveObj), err)
   141  	}
   142  
   143  	// Don't allow duplicates in the applied object.
   144  	patchObjTyped, err := f.typeConverter.ObjectToTyped(patchObj)
   145  	if err != nil {
   146  		return nil, nil, fmt.Errorf("failed to create typed patch object (%v): %v", objectGVKNN(patchObj), err)
   147  	}
   148  
   149  	liveObjTyped, err := f.typeConverter.ObjectToTyped(liveObjVersioned, typed.AllowDuplicates)
   150  	if err != nil {
   151  		return nil, nil, fmt.Errorf("failed to create typed live object (%v): %v", objectGVKNN(liveObjVersioned), err)
   152  	}
   153  
   154  	apiVersion := fieldpath.APIVersion(f.groupVersion.String())
   155  	newObjTyped, managedFields, err := f.updater.Apply(liveObjTyped, patchObjTyped, apiVersion, managed.Fields(), manager, force)
   156  	if err != nil {
   157  		return nil, nil, err
   158  	}
   159  	managed = NewManaged(managedFields, managed.Times())
   160  
   161  	if newObjTyped == nil {
   162  		return nil, managed, nil
   163  	}
   164  
   165  	newObj, err := f.typeConverter.TypedToObject(newObjTyped)
   166  	if err != nil {
   167  		return nil, nil, fmt.Errorf("failed to convert new typed object (%v) to object: %v", objectGVKNN(patchObj), err)
   168  	}
   169  
   170  	newObjVersioned, err := f.toVersioned(newObj)
   171  	if err != nil {
   172  		return nil, nil, fmt.Errorf("failed to convert new object (%v) to proper version: %v", objectGVKNN(patchObj), err)
   173  	}
   174  	f.objectDefaulter.Default(newObjVersioned)
   175  
   176  	newObjUnversioned, err := f.toUnversioned(newObjVersioned)
   177  	if err != nil {
   178  		return nil, nil, fmt.Errorf("failed to convert to unversioned (%v): %v", objectGVKNN(patchObj), err)
   179  	}
   180  	return newObjUnversioned, managed, nil
   181  }
   182  
   183  func (f *structuredMergeManager) toVersioned(obj runtime.Object) (runtime.Object, error) {
   184  	return f.objectConverter.ConvertToVersion(obj, f.groupVersion)
   185  }
   186  
   187  func (f *structuredMergeManager) toUnversioned(obj runtime.Object) (runtime.Object, error) {
   188  	return f.objectConverter.ConvertToVersion(obj, f.hubVersion)
   189  }
   190  

View as plain text