...
1 package reconcile
2
3 import (
4 "context"
5 "errors"
6
7 apierrors "k8s.io/apimachinery/pkg/api/errors"
8 kerrors "k8s.io/apimachinery/pkg/util/errors"
9 kuberecorder "k8s.io/client-go/tools/record"
10 ctrl "sigs.k8s.io/controller-runtime"
11
12 "edge-infra.dev/pkg/k8s/meta/status"
13 "edge-infra.dev/pkg/k8s/runtime/conditions"
14 "edge-infra.dev/pkg/k8s/runtime/patch"
15 )
16
17
18
19 type Conditions struct {
20
21 Target string
22
23
24 Owned []string
25
26
27 Summarize []string
28
29
30 NegativePolarity []string
31 }
32
33 func (c Conditions) IsEmpty() bool {
34 return c.Target == "" || len(c.Summarize) == 0
35 }
36
37
38
39
40 type Summarizer struct {
41 patcher *patch.SerialPatcher
42 }
43
44
45 func NewSummarizer(patcher *patch.SerialPatcher) *Summarizer {
46 return &Summarizer{
47 patcher: patcher,
48 }
49 }
50
51
52 type SummarizeOptions struct {
53
54
55 Conditions []Conditions
56
57
58
59 Processors []ResultProcessor
60
61
62 IgnoreNotFound bool
63
64 Result Result
65
66 Error error
67
68
69 FieldOwner string
70
71 EventRecorder kuberecorder.EventRecorder
72 }
73
74
75 type SummarizeOption func(*SummarizeOptions)
76
77
78
79 func WithConditions(condns ...Conditions) SummarizeOption {
80 return func(s *SummarizeOptions) {
81 s.Conditions = append(s.Conditions, condns...)
82 }
83 }
84
85
86
87 func WithProcessors(rps ...ResultProcessor) SummarizeOption {
88 return func(s *SummarizeOptions) {
89 s.Processors = append(s.Processors, rps...)
90 }
91 }
92
93
94 func WithIgnoreNotFound() SummarizeOption {
95 return func(s *SummarizeOptions) {
96 s.IgnoreNotFound = true
97 }
98 }
99
100
101
102 func WithResult(rr Result) SummarizeOption {
103 return func(s *SummarizeOptions) {
104 s.Result = rr
105 }
106 }
107
108
109
110 func WithError(re error) SummarizeOption {
111 return func(s *SummarizeOptions) {
112 s.Error = re
113 }
114 }
115
116
117 func WithFieldOwner(fieldOwner string) SummarizeOption {
118 return func(s *SummarizeOptions) {
119 s.FieldOwner = fieldOwner
120 }
121 }
122
123
124
125 func WithEventRecorder(recorder kuberecorder.EventRecorder) SummarizeOption {
126 return func(s *SummarizeOptions) {
127 s.EventRecorder = recorder
128 }
129 }
130
131
132
133
134
135
136
137 func (h *Summarizer) SummarizeAndPatch(ctx context.Context, obj conditions.Setter, options ...SummarizeOption) (ctrl.Result, error) {
138
139 opts := &SummarizeOptions{}
140 for _, o := range options {
141 o(opts)
142 }
143
144 ownedConditions := []string{}
145 for _, c := range opts.Conditions {
146 ownedConditions = append(ownedConditions, c.Owned...)
147 }
148
149
150 patchOpts := []patch.Option{
151 patch.WithOwnedConditions{
152 Conditions: ownedConditions,
153 },
154 }
155 if opts.FieldOwner != "" {
156 patchOpts = append(patchOpts, patch.WithFieldOwner(opts.FieldOwner))
157 }
158
159
160 pOpts, result, recErr := ComputeResult(obj, opts.Result, opts.Error)
161 patchOpts = append(patchOpts, pOpts...)
162
163
164
165
166 for _, c := range opts.Conditions {
167 conditions.SetSummary(obj,
168 c.Target,
169 conditions.WithConditions(c.Summarize...),
170 conditions.WithNegativePolarityConditions(c.NegativePolarity...),
171 )
172 }
173
174
175
176
177
178
179
180 if isNonStalledSuccess(obj, opts.Result, opts.Error) {
181 if !conditions.IsReady(obj) {
182 recErr = errors.New(conditions.GetMessage(obj, status.ReadyCondition))
183 }
184 }
185
186
187
188
189 if opts.Error == nil && recErr != nil {
190 opts.Error = recErr
191 }
192
193
194 for _, processor := range opts.Processors {
195 processor(ctx, opts.EventRecorder, obj, opts.Result, opts.Error)
196 }
197
198
199 if err := h.patcher.Patch(ctx, obj, patchOpts...); err != nil {
200
201 if opts.IgnoreNotFound {
202 if isNotFoundError(err) || obj.GetDeletionTimestamp().IsZero() {
203 return result, recErr
204 }
205 }
206
207 recErr = kerrors.NewAggregate([]error{recErr, err})
208 }
209
210 return result, recErr
211 }
212
213 func isNotFoundError(err error) bool {
214 var aggError kerrors.Aggregate
215 if errors.As(err, &aggError) && kerrors.FilterOut(aggError, apierrors.IsNotFound) == nil {
216 return true
217 }
218 if apierrors.IsNotFound(err) {
219 return true
220 }
221 return false
222 }
223
224
225
226 func isNonStalledSuccess(obj conditions.Setter, r Result, recErr error) bool {
227 return !conditions.IsStalled(obj) && recErr == nil && r == ResultSuccess
228 }
229
View as plain text