diff --git a/.evergreen-tasks.yml b/.evergreen-tasks.yml index 1d289fa3f..df2b2793a 100644 --- a/.evergreen-tasks.yml +++ b/.evergreen-tasks.yml @@ -1290,3 +1290,8 @@ tasks: tags: ["patch-run"] commands: - func: "e2e_test" + + - name: e2e_search_external_basic + tags: [ "patch-run" ] + commands: + - func: "e2e_test" diff --git a/.evergreen.yml b/.evergreen.yml index 94bbd5a09..dde7e1ddf 100644 --- a/.evergreen.yml +++ b/.evergreen.yml @@ -687,6 +687,7 @@ task_groups: - e2e_community_replicaset_scale - e2e_search_community_basic - e2e_search_community_tls + - e2e_search_external_basic # This is the task group that contains all the tests run in the e2e_mdb_kind_ubuntu_cloudqa build variant - name: e2e_mdb_kind_cloudqa_task_group diff --git a/api/v1/search/mongodbsearch_types.go b/api/v1/search/mongodbsearch_types.go index d77fc9b4c..b88ce5811 100644 --- a/api/v1/search/mongodbsearch_types.go +++ b/api/v1/search/mongodbsearch_types.go @@ -52,11 +52,26 @@ type MongoDBSource struct { // +optional MongoDBResourceRef *userv1.MongoDBResourceRef `json:"mongodbResourceRef,omitempty"` // +optional + ExternalMongoDBSource *ExternalMongoDBSource `json:"external,omitempty"` + // +optional PasswordSecretRef *userv1.SecretKeyRef `json:"passwordSecretRef,omitempty"` // +optional Username *string `json:"username,omitempty"` } +type ExternalMongoDBSource struct { + HostAndPorts []string `json:"hostAndPorts,omitempty"` + KeyFileSecretKeyRef *userv1.SecretKeyRef `json:"keyFileSecretRef,omitempty"` // This is the mongod credential used to connect to the external MongoDB deployment + // +optional + TLS *ExternalMongodTLS `json:"tls,omitempty"` // TLS configuration for the external MongoDB deployment +} + +type ExternalMongodTLS struct { + Enabled bool `json:"enabled"` + // +optional + CASecretRef *userv1.SecretKeyRef `json:"caSecretRef,omitempty"` +} + type Security struct { // +optional TLS TLS `json:"tls"` @@ -170,13 +185,17 @@ func (s *MongoDBSearch) GetOwnerReferences() []metav1.OwnerReference { return []metav1.OwnerReference{ownerReference} } -func (s *MongoDBSearch) GetMongoDBResourceRef() userv1.MongoDBResourceRef { +func (s *MongoDBSearch) GetMongoDBResourceRef() *userv1.MongoDBResourceRef { + if s.IsExternalMongoDBSource() { + return nil + } + mdbResourceRef := userv1.MongoDBResourceRef{Namespace: s.Namespace, Name: s.Name} if s.Spec.Source != nil && s.Spec.Source.MongoDBResourceRef != nil && s.Spec.Source.MongoDBResourceRef.Name != "" { mdbResourceRef.Name = s.Spec.Source.MongoDBResourceRef.Name } - return mdbResourceRef + return &mdbResourceRef } func (s *MongoDBSearch) GetMongotPort() int32 { @@ -201,3 +220,7 @@ func (s *MongoDBSearch) TLSOperatorSecretNamespacedName() types.NamespacedName { func (s *MongoDBSearch) GetMongotHealthCheckPort() int32 { return MongotDefautHealthCheckPort } + +func (s *MongoDBSearch) IsExternalMongoDBSource() bool { + return s.Spec.Source != nil && s.Spec.Source.ExternalMongoDBSource != nil +} diff --git a/api/v1/search/zz_generated.deepcopy.go b/api/v1/search/zz_generated.deepcopy.go index 8817e4b46..eb015e9d1 100644 --- a/api/v1/search/zz_generated.deepcopy.go +++ b/api/v1/search/zz_generated.deepcopy.go @@ -28,6 +28,56 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalMongoDBSource) DeepCopyInto(out *ExternalMongoDBSource) { + *out = *in + if in.HostAndPorts != nil { + in, out := &in.HostAndPorts, &out.HostAndPorts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.KeyFileSecretKeyRef != nil { + in, out := &in.KeyFileSecretKeyRef, &out.KeyFileSecretKeyRef + *out = new(user.SecretKeyRef) + **out = **in + } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(ExternalMongodTLS) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalMongoDBSource. +func (in *ExternalMongoDBSource) DeepCopy() *ExternalMongoDBSource { + if in == nil { + return nil + } + out := new(ExternalMongoDBSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalMongodTLS) DeepCopyInto(out *ExternalMongodTLS) { + *out = *in + if in.CASecretRef != nil { + in, out := &in.CASecretRef, &out.CASecretRef + *out = new(user.SecretKeyRef) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalMongodTLS. +func (in *ExternalMongodTLS) DeepCopy() *ExternalMongodTLS { + if in == nil { + return nil + } + out := new(ExternalMongodTLS) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MongoDBSearch) DeepCopyInto(out *MongoDBSearch) { *out = *in @@ -151,6 +201,11 @@ func (in *MongoDBSource) DeepCopyInto(out *MongoDBSource) { *out = new(user.MongoDBResourceRef) **out = **in } + if in.ExternalMongoDBSource != nil { + in, out := &in.ExternalMongoDBSource, &out.ExternalMongoDBSource + *out = new(ExternalMongoDBSource) + (*in).DeepCopyInto(*out) + } if in.PasswordSecretRef != nil { in, out := &in.PasswordSecretRef, &out.PasswordSecretRef *out = new(user.SecretKeyRef) diff --git a/controllers/operator/mongodbsearch_controller.go b/controllers/operator/mongodbsearch_controller.go index bf8a5f022..b83791f1f 100644 --- a/controllers/operator/mongodbsearch_controller.go +++ b/controllers/operator/mongodbsearch_controller.go @@ -51,31 +51,46 @@ func (r *MongoDBSearchReconciler) Reconcile(ctx context.Context, request reconci return result, err } - sourceResource, err := getSourceMongoDBForSearch(ctx, r.kubeClient, mdbSearch) + sourceResource, mdbc, err := getSourceMongoDBForSearch(ctx, r.kubeClient, mdbSearch) if err != nil { return reconcile.Result{RequeueAfter: time.Second * util.RetryTimeSec}, err } - r.mdbcWatcher.Watch(ctx, sourceResource.NamespacedName(), request.NamespacedName) + if mdbc != nil { + r.mdbcWatcher.Watch(ctx, mdbc.NamespacedName(), request.NamespacedName) + } reconcileHelper := search_controller.NewMongoDBSearchReconcileHelper(kubernetesClient.NewClient(r.kubeClient), mdbSearch, sourceResource, r.operatorSearchConfig) return reconcileHelper.Reconcile(ctx, log).ReconcileResult() } -func getSourceMongoDBForSearch(ctx context.Context, kubeClient client.Client, search *searchv1.MongoDBSearch) (search_controller.SearchSourceDBResource, error) { +func getSourceMongoDBForSearch(ctx context.Context, kubeClient client.Client, search *searchv1.MongoDBSearch) (search_controller.SearchSourceDBResource, *mdbcv1.MongoDBCommunity, error) { + if search.IsExternalMongoDBSource() { + return search_controller.NewSearchSourceDBResourceFromExternal(search.Namespace, search.Spec.Source.ExternalMongoDBSource), nil, nil + } + sourceMongoDBResourceRef := search.GetMongoDBResourceRef() + if sourceMongoDBResourceRef == nil { + return nil, nil, xerrors.New("MongoDBSearch source MongoDB resource reference is not set") + } + mdbcName := types.NamespacedName{Namespace: search.GetNamespace(), Name: sourceMongoDBResourceRef.Name} mdbc := &mdbcv1.MongoDBCommunity{} if err := kubeClient.Get(ctx, mdbcName, mdbc); err != nil { - return nil, xerrors.Errorf("error getting MongoDBCommunity %s: %w", mdbcName, err) + return nil, nil, xerrors.Errorf("error getting MongoDBCommunity %s: %w", mdbcName, err) } - return search_controller.NewSearchSourceDBResourceFromMongoDBCommunity(mdbc), nil + return search_controller.NewSearchSourceDBResourceFromMongoDBCommunity(mdbc), mdbc, nil } func mdbcSearchIndexBuilder(rawObj client.Object) []string { mdbSearch := rawObj.(*searchv1.MongoDBSearch) - return []string{mdbSearch.GetMongoDBResourceRef().Namespace + "/" + mdbSearch.GetMongoDBResourceRef().Name} + resourceRef := mdbSearch.GetMongoDBResourceRef() + if resourceRef == nil { + return []string{} + } + + return []string{resourceRef.Namespace + "/" + resourceRef.Name} } func AddMongoDBSearchController(ctx context.Context, mgr manager.Manager, operatorSearchConfig search_controller.OperatorSearchConfig) error { diff --git a/controllers/search_controller/mongodbsearch_reconcile_helper.go b/controllers/search_controller/mongodbsearch_reconcile_helper.go index 08a264853..1b0f33603 100644 --- a/controllers/search_controller/mongodbsearch_reconcile_helper.go +++ b/controllers/search_controller/mongodbsearch_reconcile_helper.go @@ -7,7 +7,6 @@ import ( "fmt" "strings" - "github.com/blang/semver" "github.com/ghodss/yaml" "go.uber.org/zap" "golang.org/x/xerrors" @@ -82,7 +81,7 @@ func (r *MongoDBSearchReconcileHelper) reconcile(ctx context.Context, log *zap.S log = log.With("MongoDBSearch", r.mdbSearch.NamespacedName()) log.Infof("Reconciling MongoDBSearch") - if err := ValidateSearchSource(r.db); err != nil { + if err := r.db.ValidateMongoDBVersion(); err != nil { return workflow.Failed(err) } @@ -123,7 +122,7 @@ func (r *MongoDBSearchReconcileHelper) reconcile(ctx context.Context, log *zap.S return workflow.Failed(err) } - if statefulSetStatus := statefulset.GetStatefulSetStatus(ctx, r.db.NamespacedName().Namespace, r.mdbSearch.StatefulSetNamespacedName().Name, r.client); !statefulSetStatus.IsOK() { + if statefulSetStatus := statefulset.GetStatefulSetStatus(ctx, r.mdbSearch.Namespace, r.mdbSearch.StatefulSetNamespacedName().Name, r.client); !statefulSetStatus.IsOK() { return statefulSetStatus } @@ -334,10 +333,7 @@ func buildSearchHeadlessService(search *searchv1.MongoDBSearch) corev1.Service { func createMongotConfig(search *searchv1.MongoDBSearch, db SearchSourceDBResource) mongot.Modification { return func(config *mongot.Config) { - var hostAndPorts []string - for i := range db.Members() { - hostAndPorts = append(hostAndPorts, fmt.Sprintf("%s-%d.%s.%s.svc.cluster.local:%d", db.Name(), i, db.DatabaseServiceName(), db.GetNamespace(), db.DatabasePort())) - } + hostAndPorts := db.HostSeeds() config.SyncSource = mongot.ConfigSyncSource{ ReplicaSet: mongot.ConfigReplicaSet{ @@ -395,23 +391,17 @@ func mongotHostAndPort(search *searchv1.MongoDBSearch) string { return fmt.Sprintf("%s.%s.svc.cluster.local:%d", svcName.Name, svcName.Namespace, search.GetMongotPort()) } -func ValidateSearchSource(db SearchSourceDBResource) error { - version, err := semver.ParseTolerant(db.GetMongoDBVersion()) - if err != nil { - return xerrors.Errorf("error parsing MongoDB version '%s': %w", db.GetMongoDBVersion(), err) - } else if version.LT(semver.MustParse("8.0.10")) { - return xerrors.New("MongoDB version must be 8.0.10 or higher") +func (r *MongoDBSearchReconcileHelper) ValidateSingleMongoDBSearchForSearchSource(ctx context.Context) error { + if r.mdbSearch.Spec.Source != nil && r.mdbSearch.Spec.Source.ExternalMongoDBSource != nil { + return nil } - return nil -} - -func (r *MongoDBSearchReconcileHelper) ValidateSingleMongoDBSearchForSearchSource(ctx context.Context) error { + ref := r.mdbSearch.GetMongoDBResourceRef() searchList := &searchv1.MongoDBSearchList{} if err := r.client.List(ctx, searchList, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(MongoDBSearchIndexFieldName, r.db.GetNamespace()+"/"+r.db.Name()), + FieldSelector: fields.OneTermEqualSelector(MongoDBSearchIndexFieldName, ref.Namespace+"/"+ref.Name), }); err != nil { - return xerrors.Errorf("Error listing MongoDBSearch resources for search source '%s': %w", r.db.Name(), err) + return xerrors.Errorf("Error listing MongoDBSearch resources for search source '%s': %w", ref.Name, err) } if len(searchList.Items) > 1 { @@ -420,7 +410,7 @@ func (r *MongoDBSearchReconcileHelper) ValidateSingleMongoDBSearchForSearchSourc resourceNames[i] = search.Name } return xerrors.Errorf( - "Found multiple MongoDBSearch resources for search source '%s': %s", r.db.Name(), + "Found multiple MongoDBSearch resources for search source '%s': %s", ref.Name, strings.Join(resourceNames, ", "), ) } diff --git a/controllers/search_controller/mongodbsearch_reconcile_helper_test.go b/controllers/search_controller/mongodbsearch_reconcile_helper_test.go index f70ec9a03..c7b4a8dc7 100644 --- a/controllers/search_controller/mongodbsearch_reconcile_helper_test.go +++ b/controllers/search_controller/mongodbsearch_reconcile_helper_test.go @@ -64,7 +64,7 @@ func TestMongoDBSearchReconcileHelper_ValidateSearchSource(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { db := NewSearchSourceDBResourceFromMongoDBCommunity(&c.mdbc) - err := ValidateSearchSource(db) + err := db.ValidateMongoDBVersion() if c.expectedError == "" { assert.NoError(t, err) } else { diff --git a/controllers/search_controller/search_construction.go b/controllers/search_controller/search_construction.go index 6aae8e982..81e756368 100644 --- a/controllers/search_controller/search_construction.go +++ b/controllers/search_controller/search_construction.go @@ -1,12 +1,15 @@ package search_controller import ( + "fmt" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + "github.com/blang/semver" searchv1 "github.com/mongodb/mongodb-kubernetes/api/v1/search" "github.com/mongodb/mongodb-kubernetes/controllers/operator/construct" mdbcv1 "github.com/mongodb/mongodb-kubernetes/mongodb-community-operator/api/v1" @@ -16,6 +19,7 @@ import ( "github.com/mongodb/mongodb-kubernetes/mongodb-community-operator/pkg/kube/probes" "github.com/mongodb/mongodb-kubernetes/pkg/statefulset" "github.com/mongodb/mongodb-kubernetes/pkg/util" + "golang.org/x/xerrors" ) const ( @@ -31,27 +35,78 @@ const ( // // TODO check if we could use already existing interface (DbCommon, MongoDBStatefulSetOwner, etc.) type SearchSourceDBResource interface { - Name() string - NamespacedName() types.NamespacedName KeyfileSecretName() string - GetNamespace() string - HasSeparateDataAndLogsVolumes() bool - DatabaseServiceName() string - DatabasePort() int - GetMongoDBVersion() string IsSecurityTLSConfigEnabled() bool TLSOperatorCASecretNamespacedName() types.NamespacedName - Members() int + HostSeeds() []string + ValidateMongoDBVersion() error } func NewSearchSourceDBResourceFromMongoDBCommunity(mdbc *mdbcv1.MongoDBCommunity) SearchSourceDBResource { return &mdbcSearchResource{db: mdbc} } +func NewSearchSourceDBResourceFromExternal(namespace string, spec *searchv1.ExternalMongoDBSource) SearchSourceDBResource { + return &externalSearchResource{namespace: namespace, spec: spec} +} + +// externalSearchResource implements SearchSourceDBResource for deployments managed outside the operator. +type externalSearchResource struct { + namespace string + spec *searchv1.ExternalMongoDBSource +} + +func (r *externalSearchResource) ValidateMongoDBVersion() error { + return nil +} + +func (r *externalSearchResource) KeyfileSecretName() string { + if r.spec.KeyFileSecretKeyRef != nil { + return r.spec.KeyFileSecretKeyRef.Name + } + + return "" +} + +func (r *externalSearchResource) IsSecurityTLSConfigEnabled() bool { + if r.spec.TLS != nil { + return r.spec.TLS.Enabled + } + return false +} + +func (r *externalSearchResource) TLSOperatorCASecretNamespacedName() types.NamespacedName { + if r.spec.TLS != nil { + return types.NamespacedName{Name: r.spec.TLS.CASecretRef.Name, Namespace: r.namespace} + } + return types.NamespacedName{} +} + +func (r *externalSearchResource) HostSeeds() []string { return r.spec.HostAndPorts } + type mdbcSearchResource struct { db *mdbcv1.MongoDBCommunity } +func (r *mdbcSearchResource) ValidateMongoDBVersion() error { + version, err := semver.ParseTolerant(r.db.GetMongoDBVersion()) + if err != nil { + return xerrors.Errorf("error parsing MongoDB version '%s': %w", r.db.GetMongoDBVersion(), err) + } else if version.LT(semver.MustParse("8.0.10")) { + return xerrors.New("MongoDB version must be 8.0.10 or higher") + } + + return nil +} + +func (r *mdbcSearchResource) HostSeeds() []string { + seeds := make([]string, r.db.Spec.Members) + for i := range seeds { + seeds[i] = fmt.Sprintf("%s-%d.%s.%s.svc.cluster.local:%d", r.db.Name, i, r.db.ServiceName(), r.db.Namespace, r.db.GetMongodConfiguration().GetDBPort()) + } + return seeds +} + func (r *mdbcSearchResource) Members() int { return r.db.Spec.Members } @@ -80,9 +135,7 @@ func (r *mdbcSearchResource) DatabaseServiceName() string { return r.db.ServiceName() } -func (r *mdbcSearchResource) GetMongoDBVersion() string { - return r.db.Spec.Version -} +// replace with a validate method that is always true for external mongodb func (r *mdbcSearchResource) IsSecurityTLSConfigEnabled() bool { return r.db.Spec.Security.TLS.Enabled @@ -161,7 +214,6 @@ func CreateSearchStatefulSetFunc(mdbSearch *searchv1.MongoDBSearch, sourceDBReso podSecurityContext, podtemplatespec.WithPodLabels(labels), podtemplatespec.WithVolumes(volumes), - podtemplatespec.WithServiceAccount(sourceDBResource.DatabaseServiceName()), podtemplatespec.WithServiceAccount(util.MongoDBServiceAccount), podtemplatespec.WithContainer(MongotContainerName, mongodbSearchContainer(mdbSearch, volumeMounts, searchImage)), ), diff --git a/docker/mongodb-kubernetes-tests/tests/search/search_community_external_mongod_basic.py b/docker/mongodb-kubernetes-tests/tests/search/search_community_external_mongod_basic.py new file mode 100644 index 000000000..f2298c069 --- /dev/null +++ b/docker/mongodb-kubernetes-tests/tests/search/search_community_external_mongod_basic.py @@ -0,0 +1,142 @@ +from kubetester import create_or_update_secret, try_load +from kubetester.kubetester import fixture as yaml_fixture +from kubetester.mongodb_community import MongoDBCommunity +from kubetester.mongodb_search import MongoDBSearch +from kubetester.phase import Phase +from pytest import fixture, mark +from tests import test_logger +from tests.common.search import movies_search_helper +from tests.common.search.movies_search_helper import SampleMoviesSearchHelper +from tests.common.search.search_tester import SearchTester +from tests.conftest import get_default_operator + +logger = test_logger.get_test_logger(__name__) + +ADMIN_USER_NAME = "mdb-admin-user" +ADMIN_USER_PASSWORD = "mdb-admin-user-pass" + +MONGOT_USER_NAME = "search-sync-source" +MONGOT_USER_PASSWORD = "search-sync-source-password" + +USER_NAME = "mdb-user" +USER_PASSWORD = "mdb-user-pass" + +MDBC_RESOURCE_NAME = "mdbc-rs" + + +@fixture(scope="function") +def mdbc(namespace: str) -> MongoDBCommunity: + resource = MongoDBCommunity.from_yaml( + yaml_fixture("community-replicaset-sample-mflix.yaml"), + name=MDBC_RESOURCE_NAME, + namespace=namespace, + ) + + # if try_load(resource): + # return resource + + mongot_host = f"{MDBC_RESOURCE_NAME}-search-svc.{namespace}.svc.cluster.local:27027" + if "additionalMongodConfig" not in resource["spec"]: + resource["spec"]["additionalMongodConfig"] = {} + if "setParameter" not in resource["spec"]["additionalMongodConfig"]: + resource["spec"]["additionalMongodConfig"]["setParameter"] = {} + + # Update the setParameter section + resource["spec"]["additionalMongodConfig"]["setParameter"].update( + { + "mongotHost": mongot_host, + "searchIndexManagementHostAndPort": mongot_host, + "skipAuthenticationToSearchIndexManagementServer": False, + "searchTLSMode": "disabled", + } + ) + + return resource + + +@fixture(scope="function") +def mdbs(namespace: str, mdbc: MongoDBCommunity) -> MongoDBSearch: + resource = MongoDBSearch.from_yaml( + yaml_fixture("search-minimal.yaml"), + namespace=namespace, + ) + + seeds = [ + f"{mdbc.name}-{i}.{mdbc.name}-svc.{namespace}.svc.cluster.local:27017" for i in range(mdbc["spec"]["members"]) + ] + + if "source" not in resource["spec"]: + resource["spec"]["source"] = {} + + resource["spec"]["source"] = { + "external": { + "hostAndPorts": seeds, + "keyFileSecretRef": {"name": f"{mdbc.name}-keyfile"}, + } + } + return resource + + +@mark.e2e_search_external_basic +def test_install_operator(namespace: str, operator_installation_config: dict[str, str]): + operator = get_default_operator(namespace, operator_installation_config=operator_installation_config) + operator.assert_is_running() + + +@mark.e2e_search_external_basic +def test_install_secrets(namespace: str, mdbs: MongoDBSearch): + create_or_update_secret(namespace=namespace, name=f"{USER_NAME}-password", data={"password": USER_PASSWORD}) + create_or_update_secret( + namespace=namespace, name=f"{ADMIN_USER_NAME}-password", data={"password": ADMIN_USER_PASSWORD} + ) + create_or_update_secret( + namespace=namespace, name=f"{mdbs.name}-{MONGOT_USER_NAME}-password", data={"password": MONGOT_USER_PASSWORD} + ) + + +@mark.e2e_search_external_basic +def test_create_database_resource(mdbc: MongoDBCommunity): + mdbc.update() + mdbc.assert_reaches_phase(Phase.Running, timeout=1000) + + +@mark.e2e_search_external_basic +def test_create_search_resource(mdbs: MongoDBSearch, mdbc: MongoDBCommunity): + mdbs.update() + mdbs.assert_reaches_phase(Phase.Running, timeout=300) + + +@mark.e2e_search_external_basic +def test_wait_for_community_resource_ready(mdbc: MongoDBCommunity): + mdbc.assert_reaches_phase(Phase.Running, timeout=1800) + + +@fixture(scope="function") +def sample_movies_helper(mdbc: MongoDBCommunity) -> SampleMoviesSearchHelper: + return movies_search_helper.SampleMoviesSearchHelper( + SearchTester(get_connection_string(mdbc, USER_NAME, USER_PASSWORD)) + ) + + +@mark.e2e_search_external_basic +def test_search_restore_sample_database(sample_movies_helper: SampleMoviesSearchHelper): + sample_movies_helper.restore_sample_database() + + +@mark.e2e_search_external_basic +def test_search_create_search_index(sample_movies_helper: SampleMoviesSearchHelper): + sample_movies_helper.create_search_index() + + +# @mark.e2e_search_external_basic +# def test_search_wait_for_search_indexes(sample_movies_helper: SampleMoviesSearchHelper): +# sample_movies_helper.wait_for_search_indexes() + + +@mark.e2e_search_external_basic +def test_search_assert_search_query(sample_movies_helper: SampleMoviesSearchHelper): + sample_movies_helper.assert_search_query(retry_timeout=60) + + +def get_connection_string(mdbc: MongoDBCommunity, user_name: str, user_password: str) -> str: + return f"mongodb://{user_name}:{user_password}@{mdbc.name}-0.{mdbc.name}-svc.{mdbc.namespace}.svc.cluster.local:27017/?replicaSet={mdbc.name}" diff --git a/mongodb-community-operator/controllers/replica_set_controller.go b/mongodb-community-operator/controllers/replica_set_controller.go index 644719294..52bbcb938 100644 --- a/mongodb-community-operator/controllers/replica_set_controller.go +++ b/mongodb-community-operator/controllers/replica_set_controller.go @@ -89,6 +89,9 @@ func NewReconciler(mgr manager.Manager, mongodbRepoUrl, mongodbImage, mongodbIma func findMdbcForSearch(ctx context.Context, rawObj k8sClient.Object) []reconcile.Request { mdbSearch := rawObj.(*searchv1.MongoDBSearch) + if mdbSearch.GetMongoDBResourceRef() == nil { + return nil // maybe empty array + } return []reconcile.Request{ {NamespacedName: types.NamespacedName{Namespace: mdbSearch.GetMongoDBResourceRef().Namespace, Name: mdbSearch.GetMongoDBResourceRef().Name}}, } @@ -713,7 +716,7 @@ func (r ReplicaSetReconciler) buildAutomationConfig(ctx context.Context, mdb mdb // for the mongod automation config. if len(searchList.Items) == 1 { searchSource := search_controller.NewSearchSourceDBResourceFromMongoDBCommunity(&mdb) - if search_controller.ValidateSearchSource(searchSource) == nil { + if searchSource.ValidateMongoDBVersion() == nil { search = &searchList.Items[0] } } @@ -834,7 +837,8 @@ func getMongodConfigModification(mdb mdbv1.MongoDBCommunity) automationconfig.Mo // getMongodConfigModification will merge the additional configuration in the CRD // into the configuration set up by the operator. func getMongodConfigSearchModification(search *searchv1.MongoDBSearch) automationconfig.Modification { - if search == nil { + // Condition for skipping add parameter if it is external mongod + if search == nil || search.IsExternalMongoDBSource() { return automationconfig.NOOP() }