1
16
17 package csaupgrade
18
19 import (
20 "bytes"
21 "encoding/json"
22 "errors"
23 "fmt"
24 "reflect"
25
26 "k8s.io/apimachinery/pkg/api/meta"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/util/sets"
30 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
31 )
32
33
34
35
36
37
38 func FindFieldsOwners(
39 managedFields []metav1.ManagedFieldsEntry,
40 operation metav1.ManagedFieldsOperationType,
41 fields *fieldpath.Set,
42 ) []metav1.ManagedFieldsEntry {
43 var result []metav1.ManagedFieldsEntry
44 for _, entry := range managedFields {
45 if entry.Operation != operation {
46 continue
47 }
48
49 fieldSet, err := decodeManagedFieldsEntrySet(entry)
50 if err != nil {
51 continue
52 }
53
54 if fields.Difference(&fieldSet).Empty() {
55 result = append(result, entry)
56 }
57 }
58 return result
59 }
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 func UpgradeManagedFields(
82 obj runtime.Object,
83 csaManagerNames sets.Set[string],
84 ssaManagerName string,
85 opts ...Option,
86 ) error {
87 o := options{}
88 for _, opt := range opts {
89 opt(&o)
90 }
91
92 accessor, err := meta.Accessor(obj)
93 if err != nil {
94 return err
95 }
96
97 filteredManagers := accessor.GetManagedFields()
98
99 for csaManagerName := range csaManagerNames {
100 filteredManagers, err = upgradedManagedFields(
101 filteredManagers, csaManagerName, ssaManagerName, o)
102
103 if err != nil {
104 return err
105 }
106 }
107
108
109 accessor.SetManagedFields(filteredManagers)
110 return nil
111 }
112
113
114
115
116
117
118
119
120
121
122 func UpgradeManagedFieldsPatch(
123 obj runtime.Object,
124 csaManagerNames sets.Set[string],
125 ssaManagerName string,
126 opts ...Option,
127 ) ([]byte, error) {
128 o := options{}
129 for _, opt := range opts {
130 opt(&o)
131 }
132
133 accessor, err := meta.Accessor(obj)
134 if err != nil {
135 return nil, err
136 }
137
138 managedFields := accessor.GetManagedFields()
139 filteredManagers := accessor.GetManagedFields()
140 for csaManagerName := range csaManagerNames {
141 filteredManagers, err = upgradedManagedFields(
142 filteredManagers, csaManagerName, ssaManagerName, o)
143 if err != nil {
144 return nil, err
145 }
146 }
147
148 if reflect.DeepEqual(managedFields, filteredManagers) {
149
150
151 return nil, nil
152 }
153
154
155
156
157
158 jsonPatch := []map[string]interface{}{
159 {
160 "op": "replace",
161 "path": "/metadata/managedFields",
162 "value": filteredManagers,
163 },
164 {
165
166
167 "op": "replace",
168 "path": "/metadata/resourceVersion",
169 "value": accessor.GetResourceVersion(),
170 },
171 }
172
173 return json.Marshal(jsonPatch)
174 }
175
176
177
178 func upgradedManagedFields(
179 managedFields []metav1.ManagedFieldsEntry,
180 csaManagerName string,
181 ssaManagerName string,
182 opts options,
183 ) ([]metav1.ManagedFieldsEntry, error) {
184 if managedFields == nil {
185 return nil, nil
186 }
187
188
189 managedFieldsCopy := make([]metav1.ManagedFieldsEntry, len(managedFields))
190 if copy(managedFieldsCopy, managedFields) != len(managedFields) {
191 return nil, errors.New("failed to copy managed fields")
192 }
193 managedFields = managedFieldsCopy
194
195
196 replaceIndex, managerExists := findFirstIndex(managedFields,
197 func(entry metav1.ManagedFieldsEntry) bool {
198 return entry.Manager == ssaManagerName &&
199 entry.Operation == metav1.ManagedFieldsOperationApply &&
200 entry.Subresource == opts.subresource
201 })
202
203 if !managerExists {
204
205
206
207
208
209 replaceIndex, managerExists = findFirstIndex(managedFields,
210 func(entry metav1.ManagedFieldsEntry) bool {
211 return entry.Manager == csaManagerName &&
212 entry.Operation == metav1.ManagedFieldsOperationUpdate &&
213 entry.Subresource == opts.subresource
214 })
215
216 if !managerExists {
217
218
219 return managedFields, nil
220 }
221
222
223 managedFields[replaceIndex].Operation = metav1.ManagedFieldsOperationApply
224 managedFields[replaceIndex].Manager = ssaManagerName
225 }
226 err := unionManagerIntoIndex(managedFields, replaceIndex, csaManagerName, opts)
227 if err != nil {
228 return nil, err
229 }
230
231
232 filteredManagers := filter(managedFields, func(entry metav1.ManagedFieldsEntry) bool {
233 return !(entry.Manager == csaManagerName &&
234 entry.Operation == metav1.ManagedFieldsOperationUpdate &&
235 entry.Subresource == opts.subresource)
236 })
237
238 return filteredManagers, nil
239 }
240
241
242
243
244 func unionManagerIntoIndex(
245 entries []metav1.ManagedFieldsEntry,
246 targetIndex int,
247 csaManagerName string,
248 opts options,
249 ) error {
250 ssaManager := entries[targetIndex]
251
252
253
254 csaManagerIndex, csaManagerExists := findFirstIndex(entries,
255 func(entry metav1.ManagedFieldsEntry) bool {
256 return entry.Manager == csaManagerName &&
257 entry.Operation == metav1.ManagedFieldsOperationUpdate &&
258 entry.Subresource == opts.subresource &&
259 entry.APIVersion == ssaManager.APIVersion
260 })
261
262 targetFieldSet, err := decodeManagedFieldsEntrySet(ssaManager)
263 if err != nil {
264 return fmt.Errorf("failed to convert fields to set: %w", err)
265 }
266
267 combinedFieldSet := &targetFieldSet
268
269
270
271 if csaManagerExists {
272 csaManager := entries[csaManagerIndex]
273
274 csaFieldSet, err := decodeManagedFieldsEntrySet(csaManager)
275 if err != nil {
276 return fmt.Errorf("failed to convert fields to set: %w", err)
277 }
278
279 combinedFieldSet = combinedFieldSet.Union(&csaFieldSet)
280 }
281
282
283 err = encodeManagedFieldsEntrySet(&entries[targetIndex], *combinedFieldSet)
284 if err != nil {
285 return fmt.Errorf("failed to encode field set: %w", err)
286 }
287
288 return nil
289 }
290
291 func findFirstIndex[T any](
292 collection []T,
293 predicate func(T) bool,
294 ) (int, bool) {
295 for idx, entry := range collection {
296 if predicate(entry) {
297 return idx, true
298 }
299 }
300
301 return -1, false
302 }
303
304 func filter[T any](
305 collection []T,
306 predicate func(T) bool,
307 ) []T {
308 result := make([]T, 0, len(collection))
309
310 for _, value := range collection {
311 if predicate(value) {
312 result = append(result, value)
313 }
314 }
315
316 if len(result) == 0 {
317 return nil
318 }
319
320 return result
321 }
322
323
324
325 func decodeManagedFieldsEntrySet(f metav1.ManagedFieldsEntry) (s fieldpath.Set, err error) {
326 err = s.FromJSON(bytes.NewReader(f.FieldsV1.Raw))
327 return s, err
328 }
329
330
331 func encodeManagedFieldsEntrySet(f *metav1.ManagedFieldsEntry, s fieldpath.Set) (err error) {
332 f.FieldsV1.Raw, err = s.ToJSON()
333 return err
334 }
335
View as plain text