1
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
43
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),
56 IgnoredFields: resetFields,
57 },
58 }, nil
59 }
60
61
62
63
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
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
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
120 func (f *structuredMergeManager) Apply(liveObj, patchObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
121
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
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