Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable watching multiple namespaces #1649

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"fmt"
"os"
"strings"

mdbv1 "github.com/mongodb/mongodb-kubernetes-operator/api/v1"
"github.com/mongodb/mongodb-kubernetes-operator/controllers"
Expand All @@ -11,6 +12,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
Expand Down Expand Up @@ -60,18 +62,20 @@ func main() {
}

// Get watch namespace from environment variable.
namespace, nsSpecified := os.LookupEnv(WatchNamespaceEnv)
namespaces, nsSpecified := os.LookupEnv(WatchNamespaceEnv)
if !nsSpecified {
log.Sugar().Fatal("No namespace specified to watch")
}

// If namespace is a wildcard use the empty string to represent all namespaces
watchNamespace := ""
if namespace == "*" {
var watchNamespaces []string
if namespaces == "*" {
log.Info("Watching all namespaces")
} else {
watchNamespace = namespace
log.Sugar().Infof("Watching namespace: %s", watchNamespace)
for _, ns := range strings.Split(namespaces, ",") {
watchNamespaces = append(watchNamespaces, strings.TrimSpace(ns))
}
log.Sugar().Infof("Watching namespace: %s", strings.Join(watchNamespaces, ","))
}

// Get a config to talk to the apiserver
Expand All @@ -82,7 +86,9 @@ func main() {

// Create a new Cmd to provide shared dependencies and start components
mgr, err := manager.New(cfg, manager.Options{
Namespace: watchNamespace,
Cache: cache.Options{
Namespaces: watchNamespaces,
},
})
if err != nil {
log.Sugar().Fatalf("Unable to create manager: %v", err)
Expand Down
11 changes: 8 additions & 3 deletions pkg/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func DependencyUpdate(chartPath string) error {
}

// Install a helm chert at the given path with the given name and the provided set arguments.
func Install(chartPath, chartName string, flags map[string]string, templateValues map[string]string) error {
func Install(chartPath, chartName string, flags map[string]string, templateValues map[string]interface{}) error {
helmArgs := []string{"install"}
helmArgs = append(helmArgs, chartName, chartPath)
for flagKey, flagValue := range flags {
Expand Down Expand Up @@ -53,10 +53,15 @@ func executeHelmCommand(args []string, messagePredicate func(string) bool) error

// mapToHelmValuesArg accepts a map of string to string and returns a list of arguments
// that can be passed to a shell helm command.
func mapToHelmValuesArg(m map[string]string) []string {
func mapToHelmValuesArg(m map[string]interface{}) []string {
var args []string
for k, v := range m {
args = append(args, "--set", fmt.Sprintf("%s=%s", k, v))
if strValue, ok := v.(string); ok {
args = append(args, "--set", fmt.Sprintf("%s=%s", k, strValue))
}
if sliceValue, ok := v.([]string); ok {
args = append(args, "--set", fmt.Sprintf("%s={%s}", k, strings.Join(sliceValue, ",")))
}
}
return args
}
7 changes: 7 additions & 0 deletions pkg/util/envvar/envvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,10 @@ func ReadBool(envVarName string) bool {
envVar := GetEnvOrDefault(envVarName, "false")
return strings.TrimSpace(strings.ToLower(envVar)) == "true"
}

func ReadCSVOrDefault(envVarName string, defaultValue []string) []string {
if val, ok := os.LookupEnv(envVarName); ok {
return strings.Split(val, ",")
}
return defaultValue
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package replica_set_multiple_namespaces

import (
"context"
"fmt"
"os"
"strings"
"testing"

"github.com/mongodb/mongodb-kubernetes-operator/test/e2e/util/mongotester"

e2eutil "github.com/mongodb/mongodb-kubernetes-operator/test/e2e"
"github.com/mongodb/mongodb-kubernetes-operator/test/e2e/mongodbtests"
"github.com/mongodb/mongodb-kubernetes-operator/test/e2e/setup"
)

const (
testWatchNamespaceEnvName = "TEST_WATCH_NAMESPACE"
testMongoDBNamespaces = "ns1,ns2"
)

func TestMain(m *testing.M) {
code, err := e2eutil.RunTest(m)
if err != nil {
fmt.Println(err)
}
os.Exit(code)
}

// TestReplicaSetMultipleNamespaces creates two MongoDB resources in separate
// namespaces to be processed by the Operator simultaneously.
func TestReplicaSetMultipleNamespaces(t *testing.T) {
t.Setenv(testWatchNamespaceEnvName, testMongoDBNamespaces)
ctx := context.Background()

testCtx := setup.Setup(ctx, t)
defer testCtx.Teardown()

for _, namespace := range strings.Split(testMongoDBNamespaces, ",") {
mdb, user := e2eutil.NewTestMongoDB(testCtx, "mdb", namespace)

_, err := setup.GeneratePasswordForUser(testCtx, user, namespace)
if err != nil {
t.Fatal(err)
}

tester, err := mongotester.FromResource(ctx, t, mdb)
if err != nil {
t.Fatal(err)
}

t.Run("Create MongoDB Resource mdb", mongodbtests.CreateMongoDBResource(&mdb, testCtx))

t.Run("mdb: Basic tests", mongodbtests.BasicFunctionality(ctx, &mdb))

t.Run("mdb: Test Basic Connectivity", tester.ConnectivitySucceeds())

t.Run("mdb: AutomationConfig has the correct version", mongodbtests.AutomationConfigVersionHasTheExpectedVersion(ctx, &mdb, 1))

t.Run("mdb: Ensure Authentication", tester.EnsureAuthenticationIsConfigured(3))
}
}
39 changes: 29 additions & 10 deletions test/e2e/setup/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ func Setup(ctx context.Context, t *testing.T) *e2eutil.TestContext {
}

config := LoadTestConfigFromEnv()
if err := ensureWatchNamespaces(testCtx, config); err != nil {
t.Fatal(err)
}
if err := DeployOperator(ctx, config, "mdb", false, false); err != nil {
t.Fatal(err)
}
Expand All @@ -57,13 +60,16 @@ func Setup(ctx context.Context, t *testing.T) *e2eutil.TestContext {
}

func SetupWithTLS(ctx context.Context, t *testing.T, resourceName string, additionalHelmArgs ...HelmArg) (*e2eutil.TestContext, TestConfig) {
textCtx, err := e2eutil.NewContext(ctx, t, envvar.ReadBool(performCleanupEnv))
testCtx, err := e2eutil.NewContext(ctx, t, envvar.ReadBool(performCleanupEnv))

if err != nil {
t.Fatal(err)
}

config := LoadTestConfigFromEnv()
if err := ensureWatchNamespaces(testCtx, config); err != nil {
t.Fatal(err)
}
if err := deployCertManager(config); err != nil {
t.Fatal(err)
}
Expand All @@ -72,7 +78,7 @@ func SetupWithTLS(ctx context.Context, t *testing.T, resourceName string, additi
t.Fatal(err)
}

return textCtx, config
return testCtx, config
}

func SetupWithTestConfig(ctx context.Context, t *testing.T, testConfig TestConfig, withTLS, defaultOperator bool, resourceName string) *e2eutil.TestContext {
Expand All @@ -88,6 +94,9 @@ func SetupWithTestConfig(ctx context.Context, t *testing.T, testConfig TestConfi
}
}

if err := ensureWatchNamespaces(testCtx, testConfig); err != nil {
t.Fatal(err)
}
if err := DeployOperator(ctx, testConfig, resourceName, withTLS, defaultOperator); err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -138,17 +147,17 @@ func extractRegistryNameAndVersion(fullImage string) (string, string, string) {
}

// getHelmArgs returns a map of helm arguments that are required to install the operator.
func getHelmArgs(testConfig TestConfig, watchNamespace string, resourceName string, withTLS bool, defaultOperator bool, additionalHelmArgs ...HelmArg) map[string]string {
func getHelmArgs(testConfig TestConfig, watchNamespaces []string, resourceName string, withTLS bool, defaultOperator bool, additionalHelmArgs ...HelmArg) map[string]interface{} {
agentRegistry, agentName, agentVersion := extractRegistryNameAndVersion(testConfig.AgentImage)
versionUpgradeHookRegistry, versionUpgradeHookName, versionUpgradeHookVersion := extractRegistryNameAndVersion(testConfig.VersionUpgradeHookImage)
readinessProbeRegistry, readinessProbeName, readinessProbeVersion := extractRegistryNameAndVersion(testConfig.ReadinessProbeImage)
operatorRegistry, operatorName, operatorVersion := extractRegistryNameAndVersion(testConfig.OperatorImage)

helmArgs := make(map[string]string)
helmArgs := make(map[string]interface{})

helmArgs["namespace"] = testConfig.Namespace

helmArgs["operator.watchNamespace"] = watchNamespace
helmArgs["operator.watchNamespaces"] = watchNamespaces

if !defaultOperator {
helmArgs["operator.operatorImageName"] = operatorName
Expand Down Expand Up @@ -189,18 +198,18 @@ func getHelmArgs(testConfig TestConfig, watchNamespace string, resourceName stri
func DeployOperator(ctx context.Context, config TestConfig, resourceName string, withTLS bool, defaultOperator bool, additionalHelmArgs ...HelmArg) error {
e2eutil.OperatorNamespace = config.Namespace
fmt.Printf("Setting operator namespace to %s\n", e2eutil.OperatorNamespace)
watchNamespace := config.Namespace
watchNamespaces := config.WatchNamespaces
if config.ClusterWide {
watchNamespace = "*"
watchNamespaces = []string{"*"}
}
fmt.Printf("Setting namespace to watch to %s\n", watchNamespace)
fmt.Printf("Setting namespace to watch to %s\n", strings.Join(watchNamespaces, ","))

helmChartName := "mongodb-kubernetes-operator"
if err := helm.Uninstall(helmChartName, config.Namespace); err != nil {
return err
}

helmArgs := getHelmArgs(config, watchNamespace, resourceName, withTLS, defaultOperator, additionalHelmArgs...)
helmArgs := getHelmArgs(config, watchNamespaces, resourceName, withTLS, defaultOperator, additionalHelmArgs...)
helmFlags := map[string]string{
"namespace": config.Namespace,
"create-namespace": "",
Expand Down Expand Up @@ -256,7 +265,7 @@ func deployCertManager(config TestConfig) error {
"namespace": config.CertManagerNamespace,
"create-namespace": "",
}
values := map[string]string{"installCRDs": "true"}
values := map[string]interface{}{"installCRDs": "true"}
if err := helm.Install(charlUrl, helmChartName, flags, values); err != nil {
return fmt.Errorf("failed to install cert-manager Helm chart: %s", err)
}
Expand All @@ -283,3 +292,13 @@ func hasDeploymentRequiredReplicas(dep *appsv1.Deployment) wait.ConditionWithCon
return false, nil
}
}

func ensureWatchNamespaces(ctx *e2eutil.TestContext, config TestConfig) error {
for _, namespace := range config.WatchNamespaces {
err := e2eutil.EnsureNamespace(ctx, namespace)
if err != nil {
return err
}
}
return nil
}
3 changes: 3 additions & 0 deletions test/e2e/setup/test_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

const (
testNamespaceEnvName = "TEST_NAMESPACE"
testWatchNamespacesEnvName = "TEST_WATCH_NAMESPACE"
testCertManagerNamespaceEnvName = "TEST_CERT_MANAGER_NAMESPACE"
testCertManagerVersionEnvName = "TEST_CERT_MANAGER_VERSION"
operatorImageEnvName = "OPERATOR_IMAGE"
Expand All @@ -18,6 +19,7 @@ const (

type TestConfig struct {
Namespace string
WatchNamespaces []string
CertManagerNamespace string
CertManagerVersion string
OperatorImage string
Expand All @@ -35,6 +37,7 @@ type TestConfig struct {
func LoadTestConfigFromEnv() TestConfig {
return TestConfig{
Namespace: envvar.GetEnvOrDefault(testNamespaceEnvName, "mongodb"),
WatchNamespaces: envvar.ReadCSVOrDefault(testWatchNamespacesEnvName, []string{"mongodb"}),
CertManagerNamespace: envvar.GetEnvOrDefault(testCertManagerNamespaceEnvName, "cert-manager"),
CertManagerVersion: envvar.GetEnvOrDefault(testCertManagerVersionEnvName, "v1.5.3"),
OperatorImage: envvar.GetEnvOrDefault(operatorImageEnvName, "quay.io/mongodb/community-operator-dev:latest"),
Expand Down