4
4
"context"
5
5
"errors"
6
6
"fmt"
7
+ "sort"
7
8
9
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
8
10
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9
11
"k8s.io/apimachinery/pkg/labels"
10
12
utilerrors "k8s.io/apimachinery/pkg/util/errors"
@@ -19,6 +21,34 @@ import (
19
21
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
20
22
)
21
23
24
+ // ReconcilerFromLegacySyncHandler returns a reconciler that invokes the given legacy sync handler and on delete funcs.
25
+ // Since the reconciler does not return an updated kubestate, it MUST be the last reconciler in a given chain.
26
+ func ReconcilerFromLegacySyncHandler (sync queueinformer.LegacySyncHandler , onDelete func (obj interface {})) kubestate.Reconciler {
27
+ var rec kubestate.ReconcilerFunc = func (ctx context.Context , in kubestate.State ) (out kubestate.State , err error ) {
28
+ out = in
29
+ switch s := in .(type ) {
30
+ case SubscriptionExistsState :
31
+ if sync != nil {
32
+ err = sync (s .Subscription ())
33
+ }
34
+ case SubscriptionDeletedState :
35
+ if onDelete != nil {
36
+ onDelete (s .Subscription ())
37
+ }
38
+ case SubscriptionState :
39
+ if sync != nil {
40
+ err = sync (s .Subscription ())
41
+ }
42
+ default :
43
+ utilruntime .HandleError (fmt .Errorf ("unexpected subscription state in legacy reconciler: %T" , s ))
44
+ }
45
+
46
+ return
47
+ }
48
+
49
+ return rec
50
+ }
51
+
22
52
// catalogHealthReconciler reconciles catalog health status for subscriptions.
23
53
type catalogHealthReconciler struct {
24
54
now func () * metav1.Time
@@ -34,47 +64,46 @@ func (c *catalogHealthReconciler) Reconcile(ctx context.Context, in kubestate.St
34
64
var prev kubestate.State
35
65
36
66
// loop until this state can no longer transition
37
- for err == nil && out == nil && next != nil && ! next .Terminal () && prev != next {
67
+ for err == nil && next != nil && next != prev && ! next .Terminal () {
38
68
select {
39
69
case <- ctx .Done ():
40
- err = errors .New ("subscription catalog health reconciliation timed out " )
70
+ err = errors .New ("subscription catalog health reconciliation context closed " )
41
71
default :
72
+ prev = next
73
+
42
74
switch s := next .(type ) {
43
75
case CatalogHealthKnownState :
44
76
// Target state already known, no work to do
45
- out = s
77
+ next = s
46
78
case CatalogHealthState :
47
79
// Gather catalog health and transition state
48
80
ns := s .Subscription ().GetNamespace ()
49
81
var catalogHealth []v1alpha1.SubscriptionCatalogHealth
50
- catalogHealth , err = c .catalogHealth (ns )
51
- if err != nil {
82
+ if catalogHealth , err = c .catalogHealth (ns ); err != nil {
52
83
break
53
84
}
54
85
55
- prev = s
56
86
next , err = s .UpdateHealth (c .now (), c .client .OperatorsV1alpha1 ().Subscriptions (ns ), catalogHealth ... )
57
87
case SubscriptionExistsState :
58
88
if s == nil {
89
+ err = errors .New ("nil state" )
59
90
break
60
91
}
61
92
if s .Subscription () == nil {
93
+ err = errors .New ("nil subscription in state" )
62
94
break
63
95
}
64
96
65
97
// Set up fresh state
66
98
next = NewCatalogHealthState (s )
67
99
default :
68
100
// Ignore all other typestates
69
- utilruntime .HandleError (fmt .Errorf ("unexpected subscription state in catalog health reconciler %T" , next ))
70
- out = s
101
+ next = s
71
102
}
72
103
}
73
104
}
74
105
75
- if prev == next {
76
- out = prev
77
- }
106
+ out = next
78
107
79
108
return
80
109
}
@@ -96,6 +125,11 @@ func (c *catalogHealthReconciler) catalogHealth(namespace string) ([]v1alpha1.Su
96
125
catalogs = append (catalogs , globals ... )
97
126
}
98
127
128
+ // Sort to ensure ordering
129
+ sort .Slice (catalogs , func (i , j int ) bool {
130
+ return catalogs [i ].GetNamespace ()+ catalogs [i ].GetName () < catalogs [j ].GetNamespace ()+ catalogs [j ].GetName ()
131
+ })
132
+
99
133
catalogHealth := make ([]v1alpha1.SubscriptionCatalogHealth , len (catalogs ))
100
134
now := c .now ()
101
135
var errs []error
@@ -151,30 +185,71 @@ func (c *catalogHealthReconciler) healthy(catalog *v1alpha1.CatalogSource) (bool
151
185
return c .registryReconcilerFactory .ReconcilerForSource (catalog ).CheckRegistryServer (catalog )
152
186
}
153
187
154
- // ReconcilerFromLegacySyncHandler returns a reconciler that invokes the given legacy sync handler and on delete funcs.
155
- // Since the reconciler does not return an updated kubestate, it MUST be the last reconciler in a given chain.
156
- func ReconcilerFromLegacySyncHandler (sync queueinformer.LegacySyncHandler , onDelete func (obj interface {})) kubestate.Reconciler {
157
- var rec kubestate.ReconcilerFunc = func (ctx context.Context , in kubestate.State ) (out kubestate.State , err error ) {
158
- out = in
159
- switch s := in .(type ) {
160
- case SubscriptionExistsState :
161
- if sync != nil {
162
- err = sync (s .Subscription ())
163
- }
164
- case SubscriptionDeletedState :
165
- if onDelete != nil {
166
- onDelete (s .Subscription ())
167
- }
168
- case SubscriptionState :
169
- if sync != nil {
170
- err = sync (s .Subscription ())
171
- }
188
+ // installPlanReconciler reconciles InstallPlan status for Subscriptions.
189
+ type installPlanReconciler struct {
190
+ now func () * metav1.Time
191
+ client versioned.Interface
192
+ installPlanLister listers.InstallPlanLister
193
+ }
194
+
195
+ // Reconcile reconciles Subscription InstallPlan conditions.
196
+ func (i * installPlanReconciler ) Reconcile (ctx context.Context , in kubestate.State ) (out kubestate.State , err error ) {
197
+ next := in
198
+ var prev kubestate.State
199
+
200
+ // loop until this state can no longer transition
201
+ for err == nil && next != nil && prev != next && ! next .Terminal () {
202
+ select {
203
+ case <- ctx .Done ():
204
+ err = errors .New ("subscription installplan reconciliation context closed" )
172
205
default :
173
- utilruntime .HandleError (fmt .Errorf ("unexpected subscription state in legacy reconciler: %T" , s ))
174
- }
206
+ prev = next
175
207
176
- return
208
+ switch s := next .(type ) {
209
+ case NoInstallPlanReferencedState :
210
+ // No InstallPlan was referenced, no work to do
211
+ next = s
212
+ case InstallPlanKnownState :
213
+ // Target state already known, no work to do
214
+ next = s
215
+ case InstallPlanReferencedState :
216
+ // Check the stated InstallPlan
217
+ ref := s .Subscription ().Status .InstallPlanRef // Should never be nil in this typestate
218
+ subClient := i .client .OperatorsV1alpha1 ().Subscriptions (ref .Namespace )
219
+
220
+ var plan * v1alpha1.InstallPlan
221
+ if plan , err = i .installPlanLister .InstallPlans (ref .Namespace ).Get (ref .Name ); err != nil {
222
+ if apierrors .IsNotFound (err ) {
223
+ next , err = s .InstallPlanNotFound (i .now (), subClient )
224
+ }
225
+
226
+ break
227
+ }
228
+
229
+ next , err = s .CheckInstallPlanStatus (i .now (), subClient , & plan .Status )
230
+ case InstallPlanState :
231
+ next = s .CheckReference ()
232
+ case SubscriptionExistsState :
233
+ if s == nil {
234
+ err = errors .New ("nil state" )
235
+ break
236
+ }
237
+ if s .Subscription () == nil {
238
+ err = errors .New ("nil subscription in state" )
239
+ break
240
+ }
241
+
242
+ // Set up fresh state
243
+ next = newInstallPlanState (s )
244
+ default :
245
+ // Ignore all other typestates
246
+ utilruntime .HandleError (fmt .Errorf ("unexpected subscription state in installplan reconciler %T" , next ))
247
+ next = s
248
+ }
249
+ }
177
250
}
178
251
179
- return rec
252
+ out = next
253
+
254
+ return
180
255
}
0 commit comments