1
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
31 type ManagedInterface interface {
32
33 Fields() fieldpath.ManagedFields
34
35
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
47 func (m *managedStruct) Fields() fieldpath.ManagedFields {
48 return m.fields
49 }
50
51
52 func (m *managedStruct) Times() map[string]*metav1.Time {
53 return m.times
54 }
55
56
57 func NewEmptyManaged() ManagedInterface {
58 return NewManaged(fieldpath.ManagedFields{}, map[string]*metav1.Time{})
59 }
60
61
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
70
71
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
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
97
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
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
134 func BuildManagerIdentifier(encodedManager *metav1.ManagedFieldsEntry) (manager string, err error) {
135 encodedManagerCopy := *encodedManager
136
137
138 encodedManagerCopy.FieldsType = ""
139
140
141 encodedManagerCopy.FieldsV1 = nil
142
143
144 encodedManagerCopy.Time = nil
145
146
147
148 if encodedManager.Operation == metav1.ManagedFieldsOperationApply {
149 encodedManagerCopy.APIVersion = ""
150 }
151
152
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
174
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
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
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