diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 4788b4bd9a..a5e20331b3 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -102,7 +102,7 @@ func main() { syncPeriod := time.Hour * 3 var cacheFunc cache.NewCacheFunc - if len(config.WatchedNamespaces) > 1 { + if len(config.WatchedNamespaces) > 0 { var namespaces []string for ns := range config.WatchedNamespaces { namespaces = append(namespaces, ns) diff --git a/test/e2e/cache_watch_test.go b/test/e2e/cache_watch_test.go new file mode 100644 index 0000000000..1743d4d651 --- /dev/null +++ b/test/e2e/cache_watch_test.go @@ -0,0 +1,151 @@ +package e2e_test + +import ( + "context" + "fmt" + "log" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/featureflags" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/e2e/config" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/e2e/k8s" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/e2e/model" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/e2e/utils" +) + +var _ = Describe("Operator watch cached namespaces as per configuration", Label("cache-watch"), func() { + DescribeTable("Operator watches one or more namespaces as per configuration inputs", + func(name string, namespaceIndexesToWatch []int, expectedNamespaceFound []bool) { + testData := model.DataProvider( + fmt.Sprintf("cache-%s", name), + model.NewEmptyAtlasKeyType().UseDefaultFullAccess(), + 30008, + []func(*model.TestDataProvider){}, + ) + + namespaces := make([]string, 3) + By("Setting up 3 test namespaces (and wait for them to be created)", func() { + for i := 0; i < 3; i++ { + namespaces[i] = utils.RandomName(fmt.Sprintf("%s-ns%d", name, i)) + log.Printf("Creating namespace %q", namespaces[i]) + Expect(k8s.CreateNamespace(testData.Context, testData.K8SClient, namespaces[i])).To(Succeed()) + } + for _, ns := range namespaces { + Eventually(func(g Gomega) bool { + namespace := &corev1.Namespace{} + return g.Expect( + testData.K8SClient.Get(testData.Context, types.NamespacedName{Name: ns}, namespace), + ).To(Succeed()) + }).WithTimeout(time.Minute).Should(BeTrue()) + log.Printf("Created namespace %q", ns) + } + }) + + secretNames := make([]string, 3) + By("Setting up 3 test secrets, one on each namespace (and wait for them)", func() { + for i, ns := range namespaces { + secretNames[i] = utils.RandomName(fmt.Sprintf("%s-secret%d", name, i)) + log.Printf("Creating secret %q at %q", secretNames[i], ns) + Expect(k8s.CreateSecret(testData.Context, testData.K8SClient, + fmt.Sprintf("publicKey%d", i), + fmt.Sprintf("privateKey%d", i), + secretNames[i], + ns, + )).To(Succeed()) + } + for i, ns := range namespaces { + Eventually(func(g Gomega) bool { + secret := &corev1.Secret{} + return g.Expect( + testData.K8SClient.Get(testData.Context, types.NamespacedName{ + Name: secretNames[i], Namespace: ns}, secret), + ).To(Succeed()) + }).WithTimeout(time.Minute).Should(BeTrue()) + log.Printf("Created secret %q at %q", secretNames[i], ns) + } + }) + + var mgr manager.Manager + By("Setting up the manager in the first namespace to watch on the given namespaces", func() { + managerConfig := &k8s.Config{ + GlobalAPISecret: client.ObjectKey{ + Namespace: namespaces[0], + Name: config.DefaultOperatorGlobalKey, + }, + FeatureFlags: featureflags.NewFeatureFlags(func() []string { return []string{} }), + } + watchedNamespaces := map[string]bool{} + for _, idx := range namespaceIndexesToWatch { + watchedNamespaces[namespaces[idx]] = true + } + if len(watchedNamespaces) > 0 { + managerConfig.WatchedNamespaces = watchedNamespaces + } + log.Printf("set watchedNamespaces to %v", managerConfig.WatchedNamespaces) + var err error + mgr, err = k8s.BuildManager(managerConfig) + Expect(err).NotTo(HaveOccurred()) + + go func(ctx context.Context) context.Context { + err := mgr.Start(ctx) + Expect(err).NotTo(HaveOccurred()) + return ctx + }(testData.Context) + }) + + By("wait for cache to be started", func() { + // the first namespace should always be cache-accessible + cache := mgr.GetCache() + Eventually(func(g Gomega) bool { + namespace := &corev1.Namespace{} + return g.Expect( + cache.Get(testData.Context, types.NamespacedName{Name: namespaces[0]}, namespace), + ).To(Succeed()) + }).WithTimeout(time.Minute).Should(BeTrue()) + }) + + By("Using the manager cache to access all 3 secrets in all 3 namespaces and checking the expected results", func() { + cache := mgr.GetCache() + for i, ns := range namespaces { + log.Printf("find secret %q at %q expected to succeed: %v", secretNames[i], ns, expectedNamespaceFound[i]) + secret := &corev1.Secret{} + err := cache.Get(testData.Context, types.NamespacedName{Name: secretNames[i], Namespace: ns}, secret) + if expectedNamespaceFound[i] { + Expect(err).To(Succeed()) + } else { + Expect(err).NotTo(Succeed()) + Expect(err.Error()).To(ContainSubstring("because of unknown namespace for the cache")) + } + } + }) + + By("Stopping the manager", func() { + //testData.ManagerContext.Done() + }) + + By("Clearing the secrets & namespaces", func() { + for i, ns := range namespaces { + log.Printf("Deleting secret %q at %q", secretNames[i], ns) + Expect(k8s.DeleteKey(testData.Context, testData.K8SClient, secretNames[i], ns)).To(Succeed()) + } + for i, ns := range namespaces { + log.Printf("Deleting secret %q at %q", secretNames[i], ns) + Expect(k8s.DeleteNamespace(testData.Context, testData.K8SClient, ns)).To(Succeed()) + } + }) + }, + Entry("No watched namespaces watches on all namespaces", + "watch-all", []int{}, []bool{true, true, true}), + Entry("One watched namespace watches only that namespace", + "watch-one", []int{0}, []bool{true, false, false}), + Entry("Two watched namespaces watches just those two namespaces", + "watch-both", []int{0, 1}, []bool{true, true, false}), + ) +}) diff --git a/test/helper/e2e/k8s/operator.go b/test/helper/e2e/k8s/operator.go index 968cdb0bff..2c3dcb7219 100644 --- a/test/helper/e2e/k8s/operator.go +++ b/test/helper/e2e/k8s/operator.go @@ -72,7 +72,7 @@ func BuildManager(initCfg *Config) (manager.Manager, error) { logger.Info("starting manager", zap.Any("config", config)) var cacheFunc cache.NewCacheFunc - if len(config.WatchedNamespaces) > 1 { + if len(config.WatchedNamespaces) > 0 { var namespaces []string for ns := range config.WatchedNamespaces { namespaces = append(namespaces, ns)