@@ -25,6 +25,7 @@ import (
25
25
26
26
"github.com/spf13/cobra"
27
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
+ apimachruntime "k8s.io/apimachinery/pkg/runtime"
28
29
"k8s.io/client-go/rest"
29
30
ctrl "sigs.k8s.io/controller-runtime"
30
31
"sigs.k8s.io/controller-runtime/pkg/cache"
@@ -45,6 +46,10 @@ import (
45
46
"github.com/operator-framework/operator-sdk/internal/helm/watches"
46
47
"github.com/operator-framework/operator-sdk/internal/util/k8sutil"
47
48
sdkVersion "github.com/operator-framework/operator-sdk/internal/version"
49
+ "helm.sh/helm/v3/pkg/chart/loader"
50
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
51
+ "k8s.io/apimachinery/pkg/labels"
52
+ "k8s.io/apimachinery/pkg/selection"
48
53
)
49
54
50
55
var log = logf .Log .WithName ("cmd" )
@@ -136,6 +141,23 @@ func run(cmd *cobra.Command, f *flags.Flags) {
136
141
// Set default manager options
137
142
options = f .ToManagerOptions (options )
138
143
144
+ if options .Scheme == nil {
145
+ options .Scheme = apimachruntime .NewScheme ()
146
+ }
147
+
148
+ ws , err := watches .Load (f .WatchesFile )
149
+ if err != nil {
150
+ log .Error (err , "Failed to create new manager factories." )
151
+ os .Exit (1 )
152
+ }
153
+
154
+ watchNamespaces := getWatchNamespaces (options .Namespace )
155
+ options .NewCache , err = buildNewCacheFunc (watchNamespaces , ws , options .Scheme )
156
+ if err != nil {
157
+ log .Error (err , "Failed to create NewCache function for manager." )
158
+ os .Exit (1 )
159
+ }
160
+
139
161
if options .NewClient == nil {
140
162
options .NewClient = func (cache cache.Cache , config * rest.Config , options client.Options , uncachedObjects ... client.Object ) (client.Client , error ) {
141
163
// Create the Client for Write operations.
@@ -152,27 +174,6 @@ func run(cmd *cobra.Command, f *flags.Flags) {
152
174
})
153
175
}
154
176
}
155
- namespace , found := os .LookupEnv (k8sutil .WatchNamespaceEnvVar )
156
- log = log .WithValues ("Namespace" , namespace )
157
- if found {
158
- log .V (1 ).Info (fmt .Sprintf ("Setting namespace with value in %s" , k8sutil .WatchNamespaceEnvVar ))
159
- if namespace == metav1 .NamespaceAll {
160
- log .Info ("Watching all namespaces." )
161
- options .Namespace = metav1 .NamespaceAll
162
- } else {
163
- if strings .Contains (namespace , "," ) {
164
- log .Info ("Watching multiple namespaces." )
165
- options .NewCache = cache .MultiNamespacedCacheBuilder (strings .Split (namespace , "," ))
166
- } else {
167
- log .Info ("Watching single namespace." )
168
- options .Namespace = namespace
169
- }
170
- }
171
- } else if options .Namespace == "" {
172
- log .Info (fmt .Sprintf ("Watch namespaces not configured by environment variable %s or file. " +
173
- "Watching all namespaces." , k8sutil .WatchNamespaceEnvVar ))
174
- options .Namespace = metav1 .NamespaceAll
175
- }
176
177
177
178
mgr , err := manager .New (cfg , options )
178
179
if err != nil {
@@ -189,11 +190,6 @@ func run(cmd *cobra.Command, f *flags.Flags) {
189
190
os .Exit (1 )
190
191
}
191
192
192
- ws , err := watches .Load (f .WatchesFile )
193
- if err != nil {
194
- log .Error (err , "Failed to create new manager factories." )
195
- os .Exit (1 )
196
- }
197
193
acg , err := helmClient .NewActionConfigGetter (mgr .GetConfig (), mgr .GetRESTMapper (), mgr .GetLogger ())
198
194
if err != nil {
199
195
log .Error (err , "Failed to create Helm action config getter" )
@@ -207,7 +203,6 @@ func run(cmd *cobra.Command, f *flags.Flags) {
207
203
}
208
204
209
205
err := controller .Add (mgr , controller.WatchOptions {
210
- Namespace : namespace ,
211
206
GVK : w .GroupVersionKind ,
212
207
ManagerFactory : release .NewManagerFactory (mgr , acg , w .ChartDir ),
213
208
ReconcilePeriod : reconcilePeriod ,
@@ -250,3 +245,84 @@ func exitIfUnsupported(options manager.Options) {
250
245
os .Exit (1 )
251
246
}
252
247
}
248
+
249
+ func getWatchNamespaces (defaultNamespace string ) []string {
250
+ namespace , found := os .LookupEnv (k8sutil .WatchNamespaceEnvVar )
251
+ log = log .WithValues ("Namespace" , namespace )
252
+ if found {
253
+ log .V (1 ).Info (fmt .Sprintf ("Setting namespace with value in %s" , k8sutil .WatchNamespaceEnvVar ))
254
+ if namespace == metav1 .NamespaceAll {
255
+ log .Info ("Watching all namespaces." )
256
+ return []string {metav1 .NamespaceAll }
257
+ }
258
+ if strings .Contains (namespace , "," ) {
259
+ log .Info ("Watching multiple namespaces." )
260
+ return strings .Split (namespace , "," )
261
+ }
262
+ log .Info ("Watching single namespace." )
263
+ return []string {namespace }
264
+ }
265
+ if defaultNamespace == "" {
266
+ log .Info (fmt .Sprintf ("Watch namespaces not configured by environment variable %s or file. " +
267
+ "Watching all namespaces." , k8sutil .WatchNamespaceEnvVar ))
268
+ return []string {metav1 .NamespaceAll }
269
+ }
270
+ return []string {defaultNamespace }
271
+ }
272
+
273
+ func buildNewCacheFunc (watchNamespaces []string , ws []watches.Watch , sch * apimachruntime.Scheme ) (cache.NewCacheFunc , error ) {
274
+ // setCacheOptions is an anonymous function that updates the cache selectors
275
+ // and namespace configuration of the cache options that are passed into it.
276
+ // we use this anonymous function in the NewCache function that we build and
277
+ // return from buildNewCacheFunc.
278
+ setCacheOptions := func (options * cache.Options ) error {
279
+ selectorsByObject := cache.SelectorsByObject {}
280
+ chartNames := make ([]string , 0 , len (ws ))
281
+ for _ , w := range ws {
282
+ sch .AddKnownTypeWithName (w .GroupVersionKind , & unstructured.Unstructured {})
283
+
284
+ crObj := & unstructured.Unstructured {}
285
+ crObj .SetGroupVersionKind (w .GroupVersionKind )
286
+ sel , err := metav1 .LabelSelectorAsSelector (& w .Selector )
287
+ if err != nil {
288
+ return fmt .Errorf ("unable to parse watch selector for %s: %v" , w .GroupVersionKind , err )
289
+ }
290
+ selectorsByObject [crObj ] = cache.ObjectSelector {Label : sel }
291
+
292
+ chrt , err := loader .LoadDir (w .ChartDir )
293
+ if err != nil {
294
+ return fmt .Errorf ("unable to load chart for %s: %v" , w .GroupVersionKind , err )
295
+ }
296
+ chartNames = append (chartNames , chrt .Name ())
297
+ }
298
+
299
+ req , err := labels .NewRequirement ("helm.sdk.operatorframework.io/chart" , selection .In , chartNames )
300
+ if err != nil {
301
+ return fmt .Errorf ("unable to create label requirement for cache default selector: %v" , err )
302
+ }
303
+ defaultSelector := labels .NewSelector ().Add (* req )
304
+
305
+ if len (watchNamespaces ) == 1 {
306
+ options .Namespace = watchNamespaces [0 ]
307
+ }
308
+ options .SelectorsByObject = selectorsByObject
309
+ options .DefaultSelector = cache.ObjectSelector {Label : defaultSelector }
310
+ return nil
311
+ }
312
+
313
+ // Define the NewCache function to use based on the number of namespaces. If there are multiple namespaces,
314
+ // use a MultiNamespacedCacheBuilder. Otherwise, use the standard New function.
315
+ newCache := cache .New
316
+ if len (watchNamespaces ) > 1 {
317
+ newCache = cache .MultiNamespacedCacheBuilder (watchNamespaces )
318
+ }
319
+
320
+ // Return a custom NewCache function that uses our setCacheOptions function
321
+ // to set the cache options as the cache is being created.
322
+ return func (config * rest.Config , opts cache.Options ) (cache.Cache , error ) {
323
+ if err := setCacheOptions (& opts ); err != nil {
324
+ return nil , err
325
+ }
326
+ return newCache (config , opts )
327
+ }, nil
328
+ }
0 commit comments