Skip to content

Commit 41d1934

Browse files
authored
add operator builder and centralize creation (#1619)
1 parent b8a2adf commit 41d1934

File tree

23 files changed

+820
-642
lines changed

23 files changed

+820
-642
lines changed

.licenses-gomod.sha256

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
100644 071ab373715c6372fbcf4212bc32597eef52773e go.mod
1+
100644 56ef1577038b01bc456601ea415f8f3045c37372 go.mod

cmd/manager/main.go

Lines changed: 27 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -23,42 +23,22 @@ import (
2323
"log"
2424
"os"
2525
"strings"
26-
"time"
27-
28-
"go.uber.org/zap/zapcore"
29-
ctrzap "sigs.k8s.io/controller-runtime/pkg/log/zap"
30-
"sigs.k8s.io/controller-runtime/pkg/webhook"
3126

3227
"github.com/go-logr/zapr"
3328
"go.uber.org/zap"
34-
corev1 "k8s.io/api/core/v1"
35-
"k8s.io/apimachinery/pkg/labels"
29+
"go.uber.org/zap/zapcore"
3630
"k8s.io/apimachinery/pkg/runtime"
3731
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
38-
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
32+
"k8s.io/client-go/kubernetes/scheme"
3933
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
4034
ctrl "sigs.k8s.io/controller-runtime"
41-
"sigs.k8s.io/controller-runtime/pkg/cache"
4235
"sigs.k8s.io/controller-runtime/pkg/client"
43-
"sigs.k8s.io/controller-runtime/pkg/healthz"
44-
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
45-
"sigs.k8s.io/controller-runtime/pkg/predicate"
4636

37+
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/collection"
4738
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/featureflags"
4839
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/kube"
4940
akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1"
50-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller"
51-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlas"
52-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlasdatabaseuser"
53-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlasdatafederation"
54-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlasdeployment"
55-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlasfederatedauth"
56-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlasproject"
57-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlassearchindexconfig"
58-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlasstream"
59-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/connectionsecret"
60-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/watch"
61-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/indexer"
41+
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/operator"
6242
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/version"
6343
)
6444

@@ -72,219 +52,43 @@ const (
7252
subobjectDeletionProtectionMessage = "Note: sub-object deletion protection is IGNORED because it does not work deterministically."
7353
)
7454

75-
var (
76-
scheme = runtime.NewScheme()
77-
setupLog = ctrl.Log.WithName("setup")
78-
)
79-
80-
func init() {
81-
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
82-
utilruntime.Must(akov2.AddToScheme(scheme))
83-
}
84-
8555
func main() {
86-
// controller-runtime/pkg/log/zap is a wrapper over zap that implements logr
87-
// logr looks quite limited in functionality so we better use Zap directly.
88-
// Though we still need the controller-runtime library and go-logr/zapr as they are used in controller-runtime
89-
// logging
90-
ctrzap.NewRaw(ctrzap.UseDevMode(true), ctrzap.StacktraceLevel(zap.ErrorLevel))
56+
akoScheme := runtime.NewScheme()
57+
utilruntime.Must(scheme.AddToScheme(akoScheme))
58+
utilruntime.Must(akov2.AddToScheme(akoScheme))
59+
60+
ctx := ctrl.SetupSignalHandler()
9161
config := parseConfiguration()
62+
9263
logger, err := initCustomZapLogger(config.LogLevel, config.LogEncoder)
9364
if err != nil {
9465
fmt.Printf("error instantiating logger: %v\r\n", err)
9566
os.Exit(1)
9667
}
9768

98-
logger.Info("starting with configuration", zap.Any("config", config), zap.Any("version", version.Version))
99-
10069
ctrl.SetLogger(zapr.NewLogger(logger))
101-
102-
syncPeriod := time.Hour * 3
103-
104-
var cacheFunc cache.NewCacheFunc
105-
if len(config.WatchedNamespaces) > 0 {
106-
var namespaces []string
107-
for ns := range config.WatchedNamespaces {
108-
namespaces = append(namespaces, ns)
109-
}
110-
cacheFunc = controller.MultiNamespacedCacheBuilder(namespaces)
111-
} else {
112-
cacheFunc = controller.CustomLabelSelectorCacheBuilder(
113-
&corev1.Secret{},
114-
labels.SelectorFromSet(labels.Set{
115-
connectionsecret.TypeLabelKey: connectionsecret.CredLabelVal,
116-
}),
117-
)
118-
}
119-
120-
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
121-
Scheme: scheme,
122-
Metrics: metricsserver.Options{BindAddress: config.MetricsAddr},
123-
WebhookServer: webhook.NewServer(webhook.Options{
124-
Port: 9443,
125-
}),
126-
Cache: cache.Options{
127-
SyncPeriod: &syncPeriod,
128-
},
129-
HealthProbeBindAddress: config.ProbeAddr,
130-
LeaderElection: config.EnableLeaderElection,
131-
LeaderElectionID: "06d035fb.mongodb.com",
132-
NewCache: cacheFunc,
133-
})
70+
setupLog := logger.Named("setup").Sugar()
71+
setupLog.Info("starting with configuration", zap.Any("config", config), zap.Any("version", version.Version))
72+
73+
mgr, err := operator.NewBuilder(operator.ManagerProviderFunc(ctrl.NewManager), akoScheme).
74+
WithConfig(ctrl.GetConfigOrDie()).
75+
WithNamespaces(collection.Keys(config.WatchedNamespaces)...).
76+
WithLogger(logger).
77+
WithMetricAddress(config.MetricsAddr).
78+
WithProbeAddress(config.ProbeAddr).
79+
WithLeaderElection(config.EnableLeaderElection).
80+
WithAtlasDomain(config.AtlasDomain).
81+
WithAPISecret(config.GlobalAPISecret).
82+
WithDeletionProtection(config.ObjectDeletionProtection).
83+
Build(ctx)
13484
if err != nil {
135-
setupLog.Error(err, "unable to start manager")
136-
os.Exit(1)
137-
}
138-
139-
ctx := ctrl.SetupSignalHandler()
140-
141-
// globalPredicates should be used for general controller Predicates
142-
// that should be applied to all controllers in order to limit the
143-
// resources they receive events for.
144-
predicateNamespaces := controller.NamespacesOrAllPredicate(config.WatchedNamespaces)
145-
globalPredicates := []predicate.Predicate{
146-
watch.CommonPredicates(), // ignore spurious changes. status changes etc.
147-
watch.SelectNamespacesPredicate(predicateNamespaces), // select only desired namespaces
148-
}
149-
150-
atlasProvider := atlas.NewProductionProvider(config.AtlasDomain, config.GlobalAPISecret, mgr.GetClient())
151-
152-
if err := indexer.RegisterAll(ctx, mgr, logger); err != nil {
153-
setupLog.Error(err, "unable to create indexers")
154-
os.Exit(1)
155-
}
156-
157-
if err = (&atlasdeployment.AtlasDeploymentReconciler{
158-
Client: mgr.GetClient(),
159-
Log: logger.Named("controllers").Named("AtlasDeployment").Sugar(),
160-
Scheme: mgr.GetScheme(),
161-
GlobalPredicates: globalPredicates,
162-
EventRecorder: mgr.GetEventRecorderFor("AtlasDeployment"),
163-
AtlasProvider: atlasProvider,
164-
ObjectDeletionProtection: config.ObjectDeletionProtection,
165-
SubObjectDeletionProtection: false,
166-
}).SetupWithManager(mgr); err != nil {
167-
setupLog.Error(err, "unable to create controller", "controller", "AtlasDeployment")
168-
os.Exit(1)
169-
}
170-
171-
if err = (&atlasproject.AtlasProjectReconciler{
172-
Client: mgr.GetClient(),
173-
Log: logger.Named("controllers").Named("AtlasProject").Sugar(),
174-
Scheme: mgr.GetScheme(),
175-
DeprecatedResourceWatcher: watch.NewDeprecatedResourceWatcher(),
176-
GlobalPredicates: globalPredicates,
177-
EventRecorder: mgr.GetEventRecorderFor("AtlasProject"),
178-
AtlasProvider: atlasProvider,
179-
ObjectDeletionProtection: config.ObjectDeletionProtection,
180-
SubObjectDeletionProtection: false,
181-
}).SetupWithManager(mgr); err != nil {
182-
setupLog.Error(err, "unable to create controller", "controller", "AtlasProject")
183-
os.Exit(1)
184-
}
185-
186-
if err = (&atlasdatabaseuser.AtlasDatabaseUserReconciler{
187-
DeprecatedResourceWatcher: watch.NewDeprecatedResourceWatcher(),
188-
Client: mgr.GetClient(),
189-
Log: logger.Named("controllers").Named("AtlasDatabaseUser").Sugar(),
190-
Scheme: mgr.GetScheme(),
191-
EventRecorder: mgr.GetEventRecorderFor("AtlasDatabaseUser"),
192-
AtlasProvider: atlasProvider,
193-
GlobalPredicates: globalPredicates,
194-
ObjectDeletionProtection: config.ObjectDeletionProtection,
195-
SubObjectDeletionProtection: false,
196-
FeaturePreviewOIDCAuthEnabled: config.FeatureFlags.IsFeaturePresent(featureflags.FeatureOIDC),
197-
}).SetupWithManager(mgr); err != nil {
198-
setupLog.Error(err, "unable to create controller", "controller", "AtlasDatabaseUser")
199-
os.Exit(1)
200-
}
201-
202-
if err = (&atlasdatafederation.AtlasDataFederationReconciler{
203-
Client: mgr.GetClient(),
204-
Log: logger.Named("controllers").Named("AtlasDataFederation").Sugar(),
205-
Scheme: mgr.GetScheme(),
206-
DeprecatedResourceWatcher: watch.NewDeprecatedResourceWatcher(),
207-
GlobalPredicates: globalPredicates,
208-
EventRecorder: mgr.GetEventRecorderFor("AtlasDataFederation"),
209-
AtlasProvider: atlasProvider,
210-
ObjectDeletionProtection: config.ObjectDeletionProtection,
211-
SubObjectDeletionProtection: false,
212-
}).SetupWithManager(mgr); err != nil {
213-
setupLog.Error(err, "unable to create controller", "controller", "AtlasDataFederation")
214-
os.Exit(1)
215-
}
216-
217-
if err = (&atlasfederatedauth.AtlasFederatedAuthReconciler{
218-
Client: mgr.GetClient(),
219-
Log: logger.Named("controllers").Named("AtlasFederatedAuth").Sugar(),
220-
Scheme: mgr.GetScheme(),
221-
DeprecatedResourceWatcher: watch.NewDeprecatedResourceWatcher(),
222-
GlobalPredicates: globalPredicates,
223-
EventRecorder: mgr.GetEventRecorderFor("AtlasFederatedAuth"),
224-
AtlasProvider: atlasProvider,
225-
ObjectDeletionProtection: config.ObjectDeletionProtection,
226-
SubObjectDeletionProtection: false,
227-
}).SetupWithManager(mgr); err != nil {
228-
setupLog.Error(err, "unable to create controller", "controller", "AtlasFederatedAuth")
229-
os.Exit(1)
230-
}
231-
232-
if err = (&atlasstream.AtlasStreamsInstanceReconciler{
233-
Scheme: mgr.GetScheme(),
234-
Client: mgr.GetClient(),
235-
EventRecorder: mgr.GetEventRecorderFor("AtlasStreamsInstance"),
236-
GlobalPredicates: globalPredicates,
237-
Log: logger.Named("controllers").Named("AtlasStreamsInstance").Sugar(),
238-
AtlasProvider: atlasProvider,
239-
ObjectDeletionProtection: config.ObjectDeletionProtection,
240-
SubObjectDeletionProtection: false,
241-
}).SetupWithManager(ctx, mgr); err != nil {
242-
setupLog.Error(err, "unable to create controller", "controller", "AtlasStreamsInstance")
243-
os.Exit(1)
244-
}
245-
246-
if err = (&atlasstream.AtlasStreamsConnectionReconciler{
247-
Scheme: mgr.GetScheme(),
248-
Client: mgr.GetClient(),
249-
EventRecorder: mgr.GetEventRecorderFor("AtlasStreamsConnection"),
250-
GlobalPredicates: globalPredicates,
251-
Log: logger.Named("controllers").Named("AtlasStreamsConnection").Sugar(),
252-
AtlasProvider: atlasProvider,
253-
ObjectDeletionProtection: config.ObjectDeletionProtection,
254-
SubObjectDeletionProtection: false,
255-
}).SetupWithManager(ctx, mgr); err != nil {
256-
setupLog.Error(err, "unable to create controller", "controller", "AtlasStreamsConnection")
257-
os.Exit(1)
258-
}
259-
260-
if err = (&atlassearchindexconfig.AtlasSearchIndexConfigReconciler{
261-
Scheme: mgr.GetScheme(),
262-
Client: mgr.GetClient(),
263-
EventRecorder: mgr.GetEventRecorderFor("AtlasSearchIndexConfig"),
264-
GlobalPredicates: globalPredicates,
265-
Log: logger.Named("controllers").Named("AtlasSearchIndexConfig").Sugar(),
266-
AtlasProvider: atlasProvider,
267-
ObjectDeletionProtection: config.ObjectDeletionProtection,
268-
SubObjectDeletionProtection: false,
269-
}).SetupWithManager(ctx, mgr); err != nil {
270-
setupLog.Error(err, "unable to create controller", "controller", "AtlasSearchIndexConfig")
271-
os.Exit(1)
272-
}
273-
274-
// +kubebuilder:scaffold:builder
275-
276-
if err := mgr.AddHealthzCheck("health", healthz.Ping); err != nil {
277-
setupLog.Error(err, "unable to set up health check")
278-
os.Exit(1)
279-
}
280-
if err := mgr.AddReadyzCheck("check", healthz.Ping); err != nil {
281-
setupLog.Error(err, "unable to set up ready check")
85+
setupLog.Error(err, "unable to start operator")
28286
os.Exit(1)
28387
}
28488

28589
setupLog.Info(subobjectDeletionProtectionMessage)
28690
setupLog.Info("starting manager")
287-
if err := mgr.Start(ctx); err != nil {
91+
if err = mgr.Start(ctx); err != nil {
28892
setupLog.Error(err, "problem running manager")
28993
os.Exit(1)
29094
}
@@ -308,7 +112,7 @@ type Config struct {
308112
func parseConfiguration() Config {
309113
var globalAPISecretName string
310114
config := Config{}
311-
flag.StringVar(&config.AtlasDomain, "atlas-domain", "https://cloud.mongodb.com/", "the Atlas URL domain name (with slash in the end).")
115+
flag.StringVar(&config.AtlasDomain, "atlas-domain", operator.DefaultAtlasDomain, "the Atlas URL domain name (with slash in the end).")
312116
flag.StringVar(&config.MetricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
313117
flag.StringVar(&config.ProbeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
314118
flag.StringVar(&globalAPISecretName, "global-api-secret-name", "", "The name of the Secret that contains Atlas API keys. "+

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ require (
8787
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
8888
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
8989
github.com/fsnotify/fsnotify v1.7.0 // indirect
90-
github.com/go-logr/logr v1.4.1 // indirect
90+
github.com/go-logr/logr v1.4.1
9191
github.com/go-openapi/jsonpointer v0.19.6 // indirect
9292
github.com/go-openapi/jsonreference v0.20.2 // indirect
9393
github.com/go-openapi/swag v0.22.3 // indirect

internal/collection/collection.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,13 @@ func CopyWithSkip[T comparable](list []T, skip T) []T {
1111

1212
return newList
1313
}
14+
15+
func Keys[K comparable, V any](m map[K]V) []K {
16+
s := make([]K, 0, len(m))
17+
18+
for k := range m {
19+
s = append(s, k)
20+
}
21+
22+
return s
23+
}

pkg/controller/atlasdatabaseuser/atlasdatabaseuser_controller.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@ import (
2929
ctrl "sigs.k8s.io/controller-runtime"
3030
"sigs.k8s.io/controller-runtime/pkg/builder"
3131
"sigs.k8s.io/controller-runtime/pkg/client"
32+
"sigs.k8s.io/controller-runtime/pkg/manager"
3233
"sigs.k8s.io/controller-runtime/pkg/predicate"
3334

35+
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/featureflags"
3436
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api"
3537
akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1"
36-
3738
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/atlas"
3839
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/connectionsecret"
3940
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/customresource"
@@ -260,3 +261,24 @@ func (r *AtlasDatabaseUserReconciler) SetupWithManager(mgr ctrl.Manager) error {
260261
Watches(&corev1.Secret{}, watch.NewSecretHandler(&r.DeprecatedResourceWatcher)).
261262
Complete(r)
262263
}
264+
265+
func NewAtlasDatabaseUserReconciler(
266+
mgr manager.Manager,
267+
predicates []predicate.Predicate,
268+
atlasProvider atlas.Provider,
269+
deletionProtection bool,
270+
featureFlags *featureflags.FeatureFlags,
271+
logger *zap.Logger,
272+
) *AtlasDatabaseUserReconciler {
273+
return &AtlasDatabaseUserReconciler{
274+
Scheme: mgr.GetScheme(),
275+
Client: mgr.GetClient(),
276+
EventRecorder: mgr.GetEventRecorderFor("AtlasDatabaseUser"),
277+
DeprecatedResourceWatcher: watch.NewDeprecatedResourceWatcher(),
278+
GlobalPredicates: predicates,
279+
Log: logger.Named("controllers").Named("AtlasDatabaseUser").Sugar(),
280+
AtlasProvider: atlasProvider,
281+
ObjectDeletionProtection: deletionProtection,
282+
FeaturePreviewOIDCAuthEnabled: featureFlags.IsFeaturePresent(featureflags.FeatureOIDC),
283+
}
284+
}

pkg/controller/atlasdatafederation/datafederation_controller.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"errors"
66
"fmt"
77

8+
"sigs.k8s.io/controller-runtime/pkg/manager"
9+
810
k8serrors "k8s.io/apimachinery/pkg/api/errors"
911
"sigs.k8s.io/controller-runtime/pkg/builder"
1012
"sigs.k8s.io/controller-runtime/pkg/event"
@@ -203,6 +205,25 @@ func (r *AtlasDataFederationReconciler) SetupWithManager(mgr ctrl.Manager) error
203205
Complete(r)
204206
}
205207

208+
func NewAtlasDataFederationReconciler(
209+
mgr manager.Manager,
210+
predicates []predicate.Predicate,
211+
atlasProvider atlas.Provider,
212+
deletionProtection bool,
213+
logger *zap.Logger,
214+
) *AtlasDataFederationReconciler {
215+
return &AtlasDataFederationReconciler{
216+
Scheme: mgr.GetScheme(),
217+
Client: mgr.GetClient(),
218+
EventRecorder: mgr.GetEventRecorderFor("AtlasDataFederation"),
219+
DeprecatedResourceWatcher: watch.NewDeprecatedResourceWatcher(),
220+
GlobalPredicates: predicates,
221+
Log: logger.Named("controllers").Named("AtlasDataFederation").Sugar(),
222+
AtlasProvider: atlasProvider,
223+
ObjectDeletionProtection: deletionProtection,
224+
}
225+
}
226+
206227
// Delete implements a handler for the Delete event
207228
func (r *AtlasDataFederationReconciler) Delete(ctx context.Context, e event.DeleteEvent) error {
208229
dataFederation, ok := e.Object.(*akov2.AtlasDataFederation)

0 commit comments

Comments
 (0)