Skip to content
Merged
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
20 changes: 15 additions & 5 deletions cmd/thv-operator/api/v1beta1/mcpexternalauthconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -660,18 +660,28 @@ type AuthServerStorageConfig struct {
}

// RedisStorageConfig configures Redis connection for auth server storage.
// Exactly one of addr (standalone) or sentinelConfig (Sentinel) must be set.
// Exactly one of addr or sentinelConfig must be set. Set clusterMode to true when
// addr points to a Redis Cluster discovery endpoint (GCP Memorystore Cluster,
// AWS ElastiCache cluster mode enabled).
//
// +kubebuilder:validation:XValidation:rule="(self.addr.size() > 0) != has(self.sentinelConfig)",message="exactly one of addr (standalone) or sentinelConfig (Sentinel) must be set"
// +kubebuilder:validation:XValidation:rule="(self.addr.size() > 0) != has(self.sentinelConfig)",message="exactly one of addr or sentinelConfig must be set"
// +kubebuilder:validation:XValidation:rule="!self.clusterMode || self.addr.size() > 0",message="clusterMode requires addr to be set"
//
//nolint:lll // CEL validation rules exceed line length limit
type RedisStorageConfig struct {
// Addr is the Redis server address for standalone mode (e.g., "host:port").
// Use for managed Redis services (GCP Memorystore, AWS ElastiCache) that present
// a single endpoint and manage HA internally. Mutually exclusive with sentinelConfig.
// Addr is the Redis server address (host:port). Required for standalone and cluster modes.
// Use for managed Redis services that expose a single endpoint (GCP Memorystore basic tier,
// AWS ElastiCache without cluster mode, or cluster-mode services when clusterMode is true).
// Mutually exclusive with sentinelConfig.
// +optional
Addr string `json:"addr,omitempty"`

// ClusterMode enables the Redis Cluster protocol. Set to true when addr points to a
// Redis Cluster discovery endpoint (e.g., GCP Memorystore Cluster, AWS ElastiCache
// cluster mode enabled). Requires addr to be set.
// +optional
ClusterMode bool `json:"clusterMode,omitempty"`

// SentinelConfig holds Redis Sentinel configuration.
// Use for self-managed Redis with Sentinel-based HA. Mutually exclusive with addr.
// +optional
Expand Down
10 changes: 5 additions & 5 deletions cmd/thv-operator/pkg/controllerutil/authserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,12 +604,11 @@ func buildStorageRunConfig(
return nil, fmt.Errorf("redis config is required when storage type is redis")
}

if redisConfig.Addr == "" && redisConfig.SentinelConfig == nil {
return nil, fmt.Errorf("either addr (standalone) or sentinel config is required for Redis storage")
}

if redisConfig.Addr != "" && redisConfig.SentinelConfig != nil {
return nil, fmt.Errorf("addr and sentinel config are mutually exclusive for Redis storage")
return nil, fmt.Errorf("addr and sentinelConfig are mutually exclusive for Redis storage")
}
if redisConfig.Addr == "" && redisConfig.SentinelConfig == nil {
return nil, fmt.Errorf("one of addr (standalone or cluster) or sentinelConfig (Sentinel) is required for Redis storage")
}

if redisConfig.ACLUserConfig == nil ||
Expand All @@ -629,6 +628,7 @@ func buildStorageRunConfig(

rc := &storage.RedisRunConfig{
Addr: redisConfig.Addr,
ClusterMode: redisConfig.ClusterMode,
AuthType: storage.AuthTypeACLUser,
ACLUserConfig: aclRunConfig,
KeyPrefix: keyPrefix,
Expand Down
36 changes: 33 additions & 3 deletions cmd/thv-operator/pkg/controllerutil/authserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1980,7 +1980,7 @@ func TestBuildStorageRunConfig(t *testing.T) {
errContains: "redis config is required",
},
{
name: "Redis storage missing both addr and sentinelConfig returns error",
name: "Redis storage missing addr and sentinelConfig returns error",
authConfig: &mcpv1beta1.EmbeddedAuthServerConfig{
Issuer: "https://auth.example.com",
Storage: &mcpv1beta1.AuthServerStorageConfig{
Expand All @@ -1994,7 +1994,7 @@ func TestBuildStorageRunConfig(t *testing.T) {
},
},
wantErr: true,
errContains: "either addr (standalone) or sentinel config is required",
errContains: "one of addr (standalone or cluster) or sentinelConfig (Sentinel) is required",
},
{
name: "Redis storage with both addr and sentinelConfig returns error",
Expand All @@ -2016,7 +2016,37 @@ func TestBuildStorageRunConfig(t *testing.T) {
},
},
wantErr: true,
errContains: "addr and sentinel config are mutually exclusive",
errContains: "mutually exclusive",
},
{
name: "Redis cluster mode builds correctly",
authConfig: &mcpv1beta1.EmbeddedAuthServerConfig{
Issuer: "https://auth.example.com",
Storage: &mcpv1beta1.AuthServerStorageConfig{
Type: mcpv1beta1.AuthServerStorageTypeRedis,
Redis: &mcpv1beta1.RedisStorageConfig{
Addr: "discovery.example.com:6379",
ClusterMode: true,
ACLUserConfig: &mcpv1beta1.RedisACLUserConfig{
UsernameSecretRef: &mcpv1beta1.SecretKeyRef{Name: "redis-secret", Key: "username"},
PasswordSecretRef: &mcpv1beta1.SecretKeyRef{Name: "redis-secret", Key: "password"},
},
},
},
},
checkFunc: func(t *testing.T, cfg *storage.RunConfig) {
t.Helper()
assert.Equal(t, string(storage.TypeRedis), cfg.Type)
require.NotNil(t, cfg.RedisConfig)
assert.Equal(t, "discovery.example.com:6379", cfg.RedisConfig.Addr)
assert.True(t, cfg.RedisConfig.ClusterMode)
assert.Nil(t, cfg.RedisConfig.SentinelConfig)
assert.Equal(t, storage.AuthTypeACLUser, cfg.RedisConfig.AuthType)
require.NotNil(t, cfg.RedisConfig.ACLUserConfig)
assert.Equal(t, authrunner.RedisUsernameEnvVar, cfg.RedisConfig.ACLUserConfig.UsernameEnvVar)
assert.Equal(t, authrunner.RedisPasswordEnvVar, cfg.RedisConfig.ACLUserConfig.PasswordEnvVar)
assert.Equal(t, "thv:auth:{default:test-server}:", cfg.RedisConfig.KeyPrefix)
},
},
{
name: "Redis storage with standalone addr builds correctly",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,17 @@ spec:
type: object
addr:
description: |-
Addr is the Redis server address for standalone mode (e.g., "host:port").
Use for managed Redis services (GCP Memorystore, AWS ElastiCache) that present
a single endpoint and manage HA internally. Mutually exclusive with sentinelConfig.
Addr is the Redis server address (host:port). Required for standalone and cluster modes.
Use for managed Redis services that expose a single endpoint (GCP Memorystore basic tier,
AWS ElastiCache without cluster mode, or cluster-mode services when clusterMode is true).
Mutually exclusive with sentinelConfig.
type: string
clusterMode:
description: |-
ClusterMode enables the Redis Cluster protocol. Set to true when addr points to a
Redis Cluster discovery endpoint (e.g., GCP Memorystore Cluster, AWS ElastiCache
cluster mode enabled). Requires addr to be set.
type: boolean
dialTimeout:
default: 5s
description: |-
Expand Down Expand Up @@ -442,9 +449,10 @@ spec:
- aclUserConfig
type: object
x-kubernetes-validations:
- message: exactly one of addr (standalone) or sentinelConfig
(Sentinel) must be set
- message: exactly one of addr or sentinelConfig must be set
rule: (self.addr.size() > 0) != has(self.sentinelConfig)
- message: clusterMode requires addr to be set
rule: '!self.clusterMode || self.addr.size() > 0'
type:
default: memory
description: |-
Expand Down Expand Up @@ -1478,10 +1486,17 @@ spec:
type: object
addr:
description: |-
Addr is the Redis server address for standalone mode (e.g., "host:port").
Use for managed Redis services (GCP Memorystore, AWS ElastiCache) that present
a single endpoint and manage HA internally. Mutually exclusive with sentinelConfig.
Addr is the Redis server address (host:port). Required for standalone and cluster modes.
Use for managed Redis services that expose a single endpoint (GCP Memorystore basic tier,
AWS ElastiCache without cluster mode, or cluster-mode services when clusterMode is true).
Mutually exclusive with sentinelConfig.
type: string
clusterMode:
description: |-
ClusterMode enables the Redis Cluster protocol. Set to true when addr points to a
Redis Cluster discovery endpoint (e.g., GCP Memorystore Cluster, AWS ElastiCache
cluster mode enabled). Requires addr to be set.
type: boolean
dialTimeout:
default: 5s
description: |-
Expand Down Expand Up @@ -1604,9 +1619,10 @@ spec:
- aclUserConfig
type: object
x-kubernetes-validations:
- message: exactly one of addr (standalone) or sentinelConfig
(Sentinel) must be set
- message: exactly one of addr or sentinelConfig must be set
rule: (self.addr.size() > 0) != has(self.sentinelConfig)
- message: clusterMode requires addr to be set
rule: '!self.clusterMode || self.addr.size() > 0'
type:
default: memory
description: |-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,17 @@ spec:
type: object
addr:
description: |-
Addr is the Redis server address for standalone mode (e.g., "host:port").
Use for managed Redis services (GCP Memorystore, AWS ElastiCache) that present
a single endpoint and manage HA internally. Mutually exclusive with sentinelConfig.
Addr is the Redis server address (host:port). Required for standalone and cluster modes.
Use for managed Redis services that expose a single endpoint (GCP Memorystore basic tier,
AWS ElastiCache without cluster mode, or cluster-mode services when clusterMode is true).
Mutually exclusive with sentinelConfig.
type: string
clusterMode:
description: |-
ClusterMode enables the Redis Cluster protocol. Set to true when addr points to a
Redis Cluster discovery endpoint (e.g., GCP Memorystore Cluster, AWS ElastiCache
cluster mode enabled). Requires addr to be set.
type: boolean
dialTimeout:
default: 5s
description: |-
Expand Down Expand Up @@ -315,9 +322,10 @@ spec:
- aclUserConfig
type: object
x-kubernetes-validations:
- message: exactly one of addr (standalone) or sentinelConfig
(Sentinel) must be set
- message: exactly one of addr or sentinelConfig must be set
rule: (self.addr.size() > 0) != has(self.sentinelConfig)
- message: clusterMode requires addr to be set
rule: '!self.clusterMode || self.addr.size() > 0'
type:
default: memory
description: |-
Expand Down Expand Up @@ -2799,10 +2807,17 @@ spec:
type: object
addr:
description: |-
Addr is the Redis server address for standalone mode (e.g., "host:port").
Use for managed Redis services (GCP Memorystore, AWS ElastiCache) that present
a single endpoint and manage HA internally. Mutually exclusive with sentinelConfig.
Addr is the Redis server address (host:port). Required for standalone and cluster modes.
Use for managed Redis services that expose a single endpoint (GCP Memorystore basic tier,
AWS ElastiCache without cluster mode, or cluster-mode services when clusterMode is true).
Mutually exclusive with sentinelConfig.
type: string
clusterMode:
description: |-
ClusterMode enables the Redis Cluster protocol. Set to true when addr points to a
Redis Cluster discovery endpoint (e.g., GCP Memorystore Cluster, AWS ElastiCache
cluster mode enabled). Requires addr to be set.
type: boolean
dialTimeout:
default: 5s
description: |-
Expand Down Expand Up @@ -2925,9 +2940,10 @@ spec:
- aclUserConfig
type: object
x-kubernetes-validations:
- message: exactly one of addr (standalone) or sentinelConfig
(Sentinel) must be set
- message: exactly one of addr or sentinelConfig must be set
rule: (self.addr.size() > 0) != has(self.sentinelConfig)
- message: clusterMode requires addr to be set
rule: '!self.clusterMode || self.addr.size() > 0'
type:
default: memory
description: |-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,17 @@ spec:
type: object
addr:
description: |-
Addr is the Redis server address for standalone mode (e.g., "host:port").
Use for managed Redis services (GCP Memorystore, AWS ElastiCache) that present
a single endpoint and manage HA internally. Mutually exclusive with sentinelConfig.
Addr is the Redis server address (host:port). Required for standalone and cluster modes.
Use for managed Redis services that expose a single endpoint (GCP Memorystore basic tier,
AWS ElastiCache without cluster mode, or cluster-mode services when clusterMode is true).
Mutually exclusive with sentinelConfig.
type: string
clusterMode:
description: |-
ClusterMode enables the Redis Cluster protocol. Set to true when addr points to a
Redis Cluster discovery endpoint (e.g., GCP Memorystore Cluster, AWS ElastiCache
cluster mode enabled). Requires addr to be set.
type: boolean
dialTimeout:
default: 5s
description: |-
Expand Down Expand Up @@ -445,9 +452,10 @@ spec:
- aclUserConfig
type: object
x-kubernetes-validations:
- message: exactly one of addr (standalone) or sentinelConfig
(Sentinel) must be set
- message: exactly one of addr or sentinelConfig must be set
rule: (self.addr.size() > 0) != has(self.sentinelConfig)
- message: clusterMode requires addr to be set
rule: '!self.clusterMode || self.addr.size() > 0'
type:
default: memory
description: |-
Expand Down Expand Up @@ -1481,10 +1489,17 @@ spec:
type: object
addr:
description: |-
Addr is the Redis server address for standalone mode (e.g., "host:port").
Use for managed Redis services (GCP Memorystore, AWS ElastiCache) that present
a single endpoint and manage HA internally. Mutually exclusive with sentinelConfig.
Addr is the Redis server address (host:port). Required for standalone and cluster modes.
Use for managed Redis services that expose a single endpoint (GCP Memorystore basic tier,
AWS ElastiCache without cluster mode, or cluster-mode services when clusterMode is true).
Mutually exclusive with sentinelConfig.
type: string
clusterMode:
description: |-
ClusterMode enables the Redis Cluster protocol. Set to true when addr points to a
Redis Cluster discovery endpoint (e.g., GCP Memorystore Cluster, AWS ElastiCache
cluster mode enabled). Requires addr to be set.
type: boolean
dialTimeout:
default: 5s
description: |-
Expand Down Expand Up @@ -1607,9 +1622,10 @@ spec:
- aclUserConfig
type: object
x-kubernetes-validations:
- message: exactly one of addr (standalone) or sentinelConfig
(Sentinel) must be set
- message: exactly one of addr or sentinelConfig must be set
rule: (self.addr.size() > 0) != has(self.sentinelConfig)
- message: clusterMode requires addr to be set
rule: '!self.clusterMode || self.addr.size() > 0'
type:
default: memory
description: |-
Expand Down
Loading
Loading