Skip to content
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
4 changes: 4 additions & 0 deletions api/v1/search/mongodbsearch_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ type MongoDBSearchStatus struct {
// +k8s:openapi-gen=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Current state of the MongoDB deployment."
// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".status.version",description="MongoDB Search version reconciled by the operator."
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The time since the MongoDB resource was created."
// +kubebuilder:resource:path=mongodbsearch,scope=Namespaced,shortName=mdbs
type MongoDBSearch struct {
Expand Down Expand Up @@ -142,6 +143,9 @@ func (s *MongoDBSearch) UpdateStatus(phase status.Phase, statusOptions ...status
if option, exists := status.GetOption(statusOptions, status.WarningsOption{}); exists {
s.Status.Warnings = append(s.Status.Warnings, option.(status.WarningsOption).Warnings...)
}
if option, exists := status.GetOption(statusOptions, MongoDBSearchVersionOption{}); exists {
s.Status.Version = option.(MongoDBSearchVersionOption).Version
}
}

func (s *MongoDBSearch) NamespacedName() types.NamespacedName {
Expand Down
17 changes: 17 additions & 0 deletions api/v1/search/status_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package search

import "github.com/mongodb/mongodb-kubernetes/api/v1/status"

type MongoDBSearchVersionOption struct {
Version string
}

var _ status.Option = MongoDBSearchVersionOption{}

func NewMongoDBSearchVersionOption(version string) MongoDBSearchVersionOption {
return MongoDBSearchVersionOption{Version: version}
}

func (o MongoDBSearchVersionOption) Value() interface{} {
return o.Version
}
7 changes: 7 additions & 0 deletions changelog/20251024_fix_mongodbsearch_status_version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: Surface reconciled MongoDBSearch version
kind: fix
date: 2025-10-24
---

* MongoDBSearch now records the reconciled mongot version in status and exposes it via a dedicated kubectl print column.
Comment on lines +1 to +7
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

40 changes: 37 additions & 3 deletions controllers/operator/mongodbsearch_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,12 @@ func TestMongoDBSearchReconcile_Success(t *testing.T) {
search.Spec.LogLevel = "WARN"

mdbc := newMongoDBCommunity("mdb", mock.TestNamespace)
reconciler, c := newSearchReconciler(mdbc, search)
operatorConfig := searchcontroller.OperatorSearchConfig{
SearchRepo: "testrepo",
SearchName: "mongot",
SearchVersion: "1.48.0",
}
reconciler, c := newSearchReconcilerWithOperatorConfig(mdbc, operatorConfig, search)

res, err := reconciler.Reconcile(
ctx,
Expand All @@ -182,6 +187,11 @@ func TestMongoDBSearchReconcile_Success(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, expected, res)

// BEFORE readiness: version should still be empty (controller sets Version only after StatefulSet ready)
searchPending := &searchv1.MongoDBSearch{}
assert.NoError(t, c.Get(ctx, types.NamespacedName{Name: search.Name, Namespace: search.Namespace}, searchPending))
assert.Empty(t, searchPending.Status.Version, "Status.Version must be empty before StatefulSet is marked ready")

svc := &corev1.Service{}
err = c.Get(ctx, search.SearchServiceNamespacedName(), svc)
assert.NoError(t, err)
Expand All @@ -194,9 +204,18 @@ func TestMongoDBSearchReconcile_Success(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, string(configYaml), cm.Data[searchcontroller.MongotConfigFilename])

sts := &appsv1.StatefulSet{}
err = c.Get(ctx, search.StatefulSetNamespacedName(), sts)
markStatefulSetReady(ctx, t, c, search.StatefulSetNamespacedName())

res, err = reconciler.Reconcile(
ctx,
reconcile.Request{NamespacedName: types.NamespacedName{Name: search.Name, Namespace: search.Namespace}},
)
assert.NoError(t, err)
assert.Equal(t, expected, res)

updatedSearch := &searchv1.MongoDBSearch{}
assert.NoError(t, c.Get(ctx, types.NamespacedName{Name: search.Name, Namespace: search.Namespace}, updatedSearch))
assert.Equal(t, operatorConfig.SearchVersion, updatedSearch.Status.Version)
}

func checkSearchReconcileFailed(
Expand Down Expand Up @@ -296,3 +315,18 @@ func TestMongoDBSearchReconcile_InvalidSearchImageVersion(t *testing.T) {
})
}
}

func markStatefulSetReady(ctx context.Context, t *testing.T, c client.Client, name types.NamespacedName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t.Helper()

sts := &appsv1.StatefulSet{}
assert.NoError(t, c.Get(ctx, name, sts))

sts.Status.UpdatedReplicas = 1
sts.Status.ReadyReplicas = 1
sts.Status.CurrentReplicas = 1
sts.Status.Replicas = 1
sts.Status.ObservedGeneration = sts.Generation

assert.NoError(t, c.Status().Update(ctx, sts))
}
38 changes: 29 additions & 9 deletions controllers/searchcontroller/mongodbsearch_reconcile_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ func (r *MongoDBSearchReconcileHelper) reconcile(ctx context.Context, log *zap.S
return workflow.Failed(err)
}

if err := r.ValidateSearchImageVersion(); err != nil {
version := r.getMongotVersion()

if err := r.ValidateSearchImageVersion(version); err != nil {
return workflow.Failed(err)
}

Expand Down Expand Up @@ -137,7 +139,7 @@ func (r *MongoDBSearchReconcileHelper) reconcile(ctx context.Context, log *zap.S
return statefulSetStatus
}

return workflow.OK()
return workflow.OK().WithAdditionalOptions(searchv1.NewMongoDBSearchVersionOption(version))
}

func (r *MongoDBSearchReconcileHelper) ensureSourceKeyfile(ctx context.Context, log *zap.SugaredLogger) (statefulset.Modification, error) {
Expand Down Expand Up @@ -435,24 +437,23 @@ func (r *MongoDBSearchReconcileHelper) ValidateSingleMongoDBSearchForSearchSourc
return nil
}

func (r *MongoDBSearchReconcileHelper) ValidateSearchImageVersion() error {
version := r.getMongotImage()

func (r *MongoDBSearchReconcileHelper) ValidateSearchImageVersion(version string) error {
if strings.Contains(version, unsupportedSearchVersion) {
return xerrors.Errorf(unsupportedSearchVersionErrorFmt, unsupportedSearchVersion)
}

return nil
}

func (r *MongoDBSearchReconcileHelper) getMongotImage() string {
func (r *MongoDBSearchReconcileHelper) getMongotVersion() string {
version := strings.TrimSpace(r.mdbSearch.Spec.Version)
if version != "" {
return version
}

if r.operatorSearchConfig.SearchVersion != "" {
return r.operatorSearchConfig.SearchVersion
version = strings.TrimSpace(r.operatorSearchConfig.SearchVersion)
if version != "" {
return version
}

if r.mdbSearch.Spec.StatefulSetConfiguration == nil {
Expand All @@ -461,13 +462,32 @@ func (r *MongoDBSearchReconcileHelper) getMongotImage() string {

for _, container := range r.mdbSearch.Spec.StatefulSetConfiguration.SpecWrapper.Spec.Template.Spec.Containers {
if container.Name == MongotContainerName {
return container.Image
return extractImageTag(container.Image)
}
}

return ""
}

func extractImageTag(image string) string {
image = strings.TrimSpace(image)
if image == "" {
return ""
}

if at := strings.Index(image, "@"); at != -1 {
image = image[:at]
}

lastSlash := strings.LastIndex(image, "/")
lastColon := strings.LastIndex(image, ":")
if lastColon > lastSlash {
return image[lastColon+1:]
}

return ""
}

func SearchCoordinatorRole() mdbv1.MongoDBRole {
// direct translation of https://github.com/10gen/mongo/blob/6f8d95a513eea8f91ea9f5d895dd8a288dfcf725/src/mongo/db/auth/builtin_roles.yml#L652
return mdbv1.MongoDBRole{
Expand Down