@@ -5,8 +5,10 @@ import (
5
5
"errors"
6
6
"fmt"
7
7
"sort"
8
+ "strings"
8
9
9
10
"github.com/sirupsen/logrus"
11
+ corev1 "k8s.io/api/core/v1"
10
12
apierrors "k8s.io/apimachinery/pkg/api/errors"
11
13
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12
14
"k8s.io/apimachinery/pkg/labels"
@@ -18,8 +20,10 @@ import (
18
20
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
19
21
listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
20
22
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/reconciler"
23
+ "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache"
21
24
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubestate"
22
25
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
26
+ "github.com/operator-framework/operator-registry/pkg/api"
23
27
)
24
28
25
29
// ReconcilerFromLegacySyncHandler returns a reconciler that invokes the given legacy sync handler and on delete funcs.
@@ -57,6 +61,7 @@ type catalogHealthReconciler struct {
57
61
catalogLister listers.CatalogSourceLister
58
62
registryReconcilerFactory reconciler.RegistryReconcilerFactory
59
63
globalCatalogNamespace string
64
+ sourceProvider cache.SourceProvider
60
65
}
61
66
62
67
// Reconcile reconciles subscription catalog health conditions.
@@ -84,7 +89,15 @@ func (c *catalogHealthReconciler) Reconcile(ctx context.Context, in kubestate.St
84
89
break
85
90
}
86
91
87
- next , err = s .UpdateHealth (c .now (), c .client .OperatorsV1alpha1 ().Subscriptions (ns ), catalogHealth ... )
92
+ var healthUpdated , deprecationUpdated bool
93
+ next , healthUpdated = s .UpdateHealth (c .now (), catalogHealth ... )
94
+ deprecationUpdated , err = c .updateDeprecatedStatus (ctx , s .Subscription ())
95
+ if err != nil {
96
+ return next , err
97
+ }
98
+ if healthUpdated || deprecationUpdated {
99
+ _ , err = c .client .OperatorsV1alpha1 ().Subscriptions (ns ).UpdateStatus (ctx , s .Subscription (), metav1.UpdateOptions {})
100
+ }
88
101
case SubscriptionExistsState :
89
102
if s == nil {
90
103
err = errors .New ("nil state" )
@@ -109,6 +122,119 @@ func (c *catalogHealthReconciler) Reconcile(ctx context.Context, in kubestate.St
109
122
return
110
123
}
111
124
125
+ // updateDeprecatedStatus adds deprecation status conditions to the subscription when present in the cache entry then
126
+ // returns a bool value of true if any changes to the existing subscription have occurred.
127
+ func (c * catalogHealthReconciler ) updateDeprecatedStatus (ctx context.Context , sub * v1alpha1.Subscription ) (bool , error ) {
128
+ if c .sourceProvider == nil {
129
+ return false , nil
130
+ }
131
+
132
+ source , ok := c .sourceProvider .Sources (sub .Namespace )[cache.SourceKey {
133
+ Name : sub .Spec .CatalogSource ,
134
+ Namespace : sub .Namespace ,
135
+ }]
136
+ if ! ok {
137
+ return false , nil
138
+ }
139
+ snapshot , err := source .Snapshot (ctx )
140
+ if err != nil {
141
+ return false , err
142
+ }
143
+ if len (snapshot .Entries ) == 0 {
144
+ return false , nil
145
+ }
146
+
147
+ changed := false
148
+ rollupMessages := []string {}
149
+ var deprecations * cache.Deprecations
150
+
151
+ found := false
152
+ for _ , entry := range snapshot .Entries {
153
+ // Find the cache entry that matches this subscription
154
+ if entry .SourceInfo == nil || entry .Package () != sub .Spec .Package {
155
+ continue
156
+ }
157
+ if sub .Spec .Channel != "" && entry .Channel () != sub .Spec .Channel {
158
+ continue
159
+ }
160
+ if sub .Status .InstalledCSV != entry .Name {
161
+ continue
162
+ }
163
+ deprecations = entry .SourceInfo .Deprecations
164
+ found = true
165
+ break
166
+ }
167
+ if ! found {
168
+ // No matching entry found
169
+ return false , nil
170
+ }
171
+ conditionTypes := []v1alpha1.SubscriptionConditionType {
172
+ v1alpha1 .SubscriptionPackageDeprecated ,
173
+ v1alpha1 .SubscriptionChannelDeprecated ,
174
+ v1alpha1 .SubscriptionBundleDeprecated ,
175
+ }
176
+ for _ , conditionType := range conditionTypes {
177
+ oldCondition := sub .Status .GetCondition (conditionType )
178
+ var deprecation * api.Deprecation
179
+ if deprecations != nil {
180
+ switch conditionType {
181
+ case v1alpha1 .SubscriptionPackageDeprecated :
182
+ deprecation = deprecations .Package
183
+ case v1alpha1 .SubscriptionChannelDeprecated :
184
+ deprecation = deprecations .Channel
185
+ case v1alpha1 .SubscriptionBundleDeprecated :
186
+ deprecation = deprecations .Bundle
187
+ }
188
+ }
189
+ if deprecation != nil {
190
+ if conditionType == v1alpha1 .SubscriptionChannelDeprecated && sub .Spec .Channel == "" {
191
+ // Special case: If optional field sub.Spec.Channel is unset do not apply a channel
192
+ // deprecation message and remove them if any exist.
193
+ sub .Status .RemoveConditions (conditionType )
194
+ if oldCondition .Status == corev1 .ConditionTrue {
195
+ changed = true
196
+ }
197
+ continue
198
+ }
199
+ newCondition := v1alpha1.SubscriptionCondition {
200
+ Type : conditionType ,
201
+ Message : deprecation .Message ,
202
+ Status : corev1 .ConditionTrue ,
203
+ LastTransitionTime : c .now (),
204
+ }
205
+ rollupMessages = append (rollupMessages , deprecation .Message )
206
+ if oldCondition .Message != newCondition .Message {
207
+ // oldCondition's message was empty or has changed; add or update the condition
208
+ sub .Status .SetCondition (newCondition )
209
+ changed = true
210
+ }
211
+ } else if oldCondition .Status == corev1 .ConditionTrue {
212
+ // No longer deprecated at this level; remove the condition
213
+ sub .Status .RemoveConditions (conditionType )
214
+ changed = true
215
+ }
216
+ }
217
+
218
+ if ! changed {
219
+ // No need to update rollup condition if no other conditions have changed
220
+ return false , nil
221
+ }
222
+ if len (rollupMessages ) > 0 {
223
+ rollupCondition := v1alpha1.SubscriptionCondition {
224
+ Type : v1alpha1 .SubscriptionDeprecated ,
225
+ Message : strings .Join (rollupMessages , "; " ),
226
+ Status : corev1 .ConditionTrue ,
227
+ LastTransitionTime : c .now (),
228
+ }
229
+ sub .Status .SetCondition (rollupCondition )
230
+ } else {
231
+ // No rollup message means no deprecation conditions were set; remove the rollup if it exists
232
+ sub .Status .RemoveConditions (v1alpha1 .SubscriptionDeprecated )
233
+ }
234
+
235
+ return true , nil
236
+ }
237
+
112
238
// catalogHealth gets the health of catalogs that can affect Susbcriptions in the given namespace.
113
239
// This means all catalogs in the given namespace, as well as any catalogs in the operator's global catalog namespace.
114
240
func (c * catalogHealthReconciler ) catalogHealth (namespace string ) ([]v1alpha1.SubscriptionCatalogHealth , error ) {
0 commit comments