Skip to content

Commit 44a12a2

Browse files
committed
Sharded multiple mongot: review fixes (#827)
Fixes to search with multiple-mongot # Conflicts: # controllers/searchcontroller/mongodbsearch_reconcile_helper.go
1 parent f19a181 commit 44a12a2

File tree

14 files changed

+81
-543
lines changed

14 files changed

+81
-543
lines changed

api/v1/search/mongodbsearch_types.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ type MongoDBSearchSpec struct {
5656
// +optional
5757
Source *MongoDBSource `json:"source"`
5858
// Replicas is the number of mongot pods to deploy.
59-
// For ReplicaSet source: this many mongot pods total.
60-
// For Sharded source: this many mongot pods per shard.
61-
// When Replicas > 1, a load balancer configuration (lb.mode: Unmanaged with lb.endpoint)
59+
// For ReplicaSet source: the number of mongot pods in total.
60+
// For Sharded source: the number mongot pods per shard.
61+
// When Replicas > 1, a load balancer configuration (spec.lb)
6262
// is required to distribute traffic across mongot instances.
6363
// +optional
6464
// +kubebuilder:validation:Minimum=1
@@ -88,7 +88,7 @@ type MongoDBSearchSpec struct {
8888
// `embedding` field of mongot config is generated using the values provided here.
8989
// +optional
9090
AutoEmbedding *EmbeddingConfig `json:"autoEmbedding,omitempty"`
91-
// LoadBalancer configures how mongod/mongos connect to mongot (Managed vs Unmanaged/BYO LB).
91+
// LoadBalancer configures how mongod/mongos connect to mongot (Managed vs Unmanaged/BYO Load Balancer).
9292
// +optional
9393
LoadBalancer *LoadBalancerConfig `json:"lb,omitempty"`
9494
}
@@ -98,19 +98,21 @@ type MongoDBSearchSpec struct {
9898
type LBMode string
9999

100100
const (
101-
// LBModeManaged indicates operator-managed Envoy load balancer
101+
// LBModeManaged indicates operator-managed load balancer
102102
LBModeManaged LBMode = "Managed"
103103
// LBModeUnmanaged indicates user-provided L7 load balancer (BYO LB)
104104
LBModeUnmanaged LBMode = "Unmanaged"
105105
)
106106

107107
// LoadBalancerConfig configures how mongod/mongos connect to mongot
108108
type LoadBalancerConfig struct {
109-
// Mode specifies the load balancer mode: Managed (operator-managed) or Unmanaged (BYO L7 LB)
109+
// Mode specifies the load balancer mode: Managed (operator-managed) or Unmanaged (BYO L7 Load Balancer)
110110
// +kubebuilder:validation:Required
111111
Mode LBMode `json:"mode"`
112112
// Endpoint is the LB endpoint for ReplicaSet, or a template for sharded clusters.
113-
// For sharded clusters, use {shardName} as a placeholder substituted with the actual shard name.
113+
// For sharded clusters, at least one {shardName} placeholder must be present and will be substituted with the actual shard name.
114+
// Each shard must connect to their mongots using a shard-unique endpoint to allow LoadBalancer to
115+
// route the traffic to the mongot instances for that shard.
114116
// Example: "lb-{shardName}.example.com:27028"
115117
// +optional
116118
Endpoint string `json:"endpoint,omitempty"`
@@ -452,7 +454,7 @@ func (s *MongoDBSearch) IsLBModeUnmanaged() bool {
452454
return s.Spec.LoadBalancer != nil && s.Spec.LoadBalancer.Mode == LBModeUnmanaged
453455
}
454456

455-
// IsReplicaSetUnmanagedLB returns true if this is a ReplicaSet unmanaged LB configuration.
457+
// IsReplicaSetUnmanagedLB returns true if this is a ReplicaSet with unmanaged LB configuration.
456458
// An endpoint with a template placeholder ({shardName}) is NOT considered a ReplicaSet endpoint.
457459
func (s *MongoDBSearch) IsReplicaSetUnmanagedLB() bool {
458460
return s.IsLBModeUnmanaged() &&

api/v1/search/mongodbsearch_validation.go

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
v1 "github.com/mongodb/mongodb-kubernetes/api/v1"
88
)
99

10-
// ValidateSpec validates the MongoDBSearch spec
1110
func (s *MongoDBSearch) ValidateSpec() error {
1211
for _, res := range s.RunValidations() {
1312
if res.Level == v1.ErrorLevel {
@@ -17,13 +16,11 @@ func (s *MongoDBSearch) ValidateSpec() error {
1716
return nil
1817
}
1918

20-
// RunValidations runs all validation rules and returns the results
2119
func (s *MongoDBSearch) RunValidations() []v1.ValidationResult {
2220
validators := []func(*MongoDBSearch) v1.ValidationResult{
2321
validateLBConfig,
2422
validateUnmanagedLBConfig,
2523
validateEndpointTemplate,
26-
validateTLSConfig,
2724
}
2825

2926
var results []v1.ValidationResult
@@ -36,7 +33,6 @@ func (s *MongoDBSearch) RunValidations() []v1.ValidationResult {
3633
return results
3734
}
3835

39-
// validateLBConfig validates the load balancer configuration
4036
func validateLBConfig(s *MongoDBSearch) v1.ValidationResult {
4137
if s.Spec.LoadBalancer == nil {
4238
// LB config is optional
@@ -77,31 +73,16 @@ func validateEndpointTemplate(s *MongoDBSearch) v1.ValidationResult {
7773

7874
endpoint := s.Spec.LoadBalancer.Endpoint
7975

80-
// Template must contain exactly one {shardName} placeholder
8176
count := strings.Count(endpoint, ShardNamePlaceholder)
82-
if count != 1 {
83-
return v1.ValidationError("spec.lb.endpoint template must contain exactly one %s placeholder, found %d", ShardNamePlaceholder, count)
77+
if count == 0 {
78+
return v1.ValidationError("spec.lb.endpoint template must contain at least one %s placeholder to differentiate between shards, found %d", ShardNamePlaceholder, count)
8479
}
8580

86-
// Template should have some content before or after the placeholder
87-
if endpoint == ShardNamePlaceholder {
88-
return v1.ValidationError("spec.lb.endpoint template must contain more than just the %s placeholder", ShardNamePlaceholder)
81+
// Endpoint must contain more than just the placeholder(s)
82+
stripped := strings.TrimSpace(strings.ReplaceAll(endpoint, ShardNamePlaceholder, ""))
83+
if stripped == "" {
84+
return v1.ValidationError("spec.lb.endpoint must contain more than just the %s placeholder", ShardNamePlaceholder)
8985
}
9086

9187
return v1.ValidationSuccess()
9288
}
93-
94-
// validateTLSConfig validates the TLS configuration
95-
func validateTLSConfig(s *MongoDBSearch) v1.ValidationResult {
96-
if s.Spec.Security.TLS == nil {
97-
return v1.ValidationSuccess()
98-
}
99-
100-
// TLS is valid in all cases:
101-
// 1. CertificateKeySecret.Name is specified - use explicit secret name
102-
// 2. CertsSecretPrefix is specified - use {prefix}-{resourceName}-search-cert
103-
// 3. Both are empty - use default {resourceName}-search-cert
104-
// No validation error needed as we always have a valid fallback
105-
106-
return v1.ValidationSuccess()
107-
}

config/crd/bases/mongodb.com_mongodbsearch.yaml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,14 @@ spec:
8080
type: object
8181
lb:
8282
description: LoadBalancer configures how mongod/mongos connect to
83-
mongot (Managed vs Unmanaged/BYO LB).
83+
mongot (Managed vs Unmanaged/BYO Load Balancer).
8484
properties:
8585
endpoint:
8686
description: |-
8787
Endpoint is the LB endpoint for ReplicaSet, or a template for sharded clusters.
88-
For sharded clusters, use {shardName} as a placeholder substituted with the actual shard name.
88+
For sharded clusters, at least one {shardName} placeholder must be present and will be substituted with the actual shard name.
89+
Each shard must connect to their mongots using a shard-unique endpoint to allow LoadBalancer to
90+
route the traffic to the mongot instances for that shard.
8991
Example: "lb-{shardName}.example.com:27028"
9092
type: string
9193
envoy:
@@ -94,7 +96,7 @@ spec:
9496
type: object
9597
mode:
9698
description: 'Mode specifies the load balancer mode: Managed (operator-managed)
97-
or Unmanaged (BYO L7 LB)'
99+
or Unmanaged (BYO L7 Load Balancer)'
98100
enum:
99101
- Managed
100102
- Unmanaged
@@ -176,9 +178,9 @@ spec:
176178
default: 1
177179
description: |-
178180
Replicas is the number of mongot pods to deploy.
179-
For ReplicaSet source: this many mongot pods total.
180-
For Sharded source: this many mongot pods per shard.
181-
When Replicas > 1, a load balancer configuration (lb.mode: Unmanaged with lb.endpoint)
181+
For ReplicaSet source: the number of mongot pods in total.
182+
For Sharded source: the number mongot pods per shard.
183+
When Replicas > 1, a load balancer configuration (spec.lb)
182184
is required to distribute traffic across mongot instances.
183185
minimum: 1
184186
type: integer

controllers/operator/mongodbshardedcluster_controller.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,6 @@ func (r *ShardedClusterReconcileHelper) applySearchParametersForShards(ctx conte
10221022

10231023
log.Infof("Applying search parameters from MongoDBSearch %s", search.NamespacedName())
10241024

1025-
// Collect shard names for mongos configuration
10261025
shardNames := make([]string, sc.Spec.ShardCount)
10271026
for shardIdx := 0; shardIdx < sc.Spec.ShardCount; shardIdx++ {
10281027
shardNames[shardIdx] = sc.ShardRsName(shardIdx)

controllers/searchcontroller/enterprise_search_source_test.go

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -372,40 +372,3 @@ func TestShardedEnterpriseSearchSource_GetShardNames(t *testing.T) {
372372
})
373373
}
374374
}
375-
376-
func TestShardedEnterpriseSearchSource_Validate(t *testing.T) {
377-
tests := []struct {
378-
name string
379-
shardCount int
380-
expectError bool
381-
expectedErrMsg string
382-
}{
383-
{
384-
name: "Valid - two shards",
385-
shardCount: 2,
386-
expectError: false,
387-
},
388-
{
389-
name: "Valid - single shard",
390-
shardCount: 1,
391-
expectError: false,
392-
},
393-
}
394-
395-
for _, tc := range tests {
396-
t.Run(tc.name, func(t *testing.T) {
397-
mdb := newShardedClusterMongoDB("my-cluster", "test-ns", tc.shardCount, "8.2.0")
398-
search := newShardedUnmanagedLBSearch("test-search", "test-ns", "my-cluster", "")
399-
src := NewShardedEnterpriseSearchSource(mdb, search)
400-
401-
err := src.Validate()
402-
403-
if tc.expectError {
404-
assert.Error(t, err)
405-
assert.Contains(t, err.Error(), tc.expectedErrMsg)
406-
} else {
407-
assert.NoError(t, err)
408-
}
409-
})
410-
}
411-
}

controllers/searchcontroller/mongodbsearch_reconcile_helper.go

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,6 @@ func (r *MongoDBSearchReconcileHelper) reconcile(ctx context.Context, log *zap.S
125125
return workflow.Failed(err)
126126
}
127127

128-
if err := r.ValidateAutoEmbeddingConfig(); err != nil {
129-
return workflow.Failed(err)
130-
}
131-
132128
if shardedSource, ok := r.db.(SearchSourceShardedDeployment); ok {
133129
return r.reconcileSharded(ctx, log, shardedSource, version)
134130
}
@@ -1057,7 +1053,7 @@ func (r *MongoDBSearchReconcileHelper) ValidateMultipleReplicasConfig() error {
10571053
if !r.mdbSearch.IsShardedUnmanagedLB() {
10581054
return xerrors.Errorf(
10591055
"multiple mongot replicas (%d) require unmanaged load balancer configuration; "+
1060-
"please configure spec.lb.mode=Unmanaged with spec.lb.endpoint for sharded clusters",
1056+
"please configure load balancing in spec.lb.",
10611057
r.mdbSearch.GetReplicas(),
10621058
)
10631059
}
@@ -1068,26 +1064,7 @@ func (r *MongoDBSearchReconcileHelper) ValidateMultipleReplicasConfig() error {
10681064
if !r.mdbSearch.IsReplicaSetUnmanagedLB() {
10691065
return xerrors.Errorf(
10701066
"multiple mongot replicas (%d) require unmanaged load balancer configuration; "+
1071-
"please configure spec.lb.mode=Unmanaged with spec.lb.endpoint",
1072-
r.mdbSearch.GetReplicas(),
1073-
)
1074-
}
1075-
1076-
return nil
1077-
}
1078-
1079-
// ValidateAutoEmbeddingConfig validates that auto embeddings are not configured with multiple mongot replicas.
1080-
// Auto embeddings require the IsAutoEmbeddingViewWriter flag to be set to true for exactly one mongot instance.
1081-
// When multiple replicas are configured, all mongot instances would have this flag set to true, causing conflicts.
1082-
func (r *MongoDBSearchReconcileHelper) ValidateAutoEmbeddingConfig() error {
1083-
if r.mdbSearch.Spec.AutoEmbedding == nil {
1084-
return nil
1085-
}
1086-
1087-
if r.mdbSearch.HasMultipleReplicas() {
1088-
return xerrors.Errorf(
1089-
"auto embeddings are not supported with multiple mongot replicas (%d); "+
1090-
"please set spec.source.replicas to 1 or remove spec.autoEmbedding",
1067+
"please configure load balancing in spec.lb.",
10911068
r.mdbSearch.GetReplicas(),
10921069
)
10931070
}

0 commit comments

Comments
 (0)