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
75 changes: 75 additions & 0 deletions cmd/operator/app/thread_keeper_label_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package app

import (
"testing"

meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/event"

api "github.com/altinity/clickhouse-operator/pkg/apis/clickhouse-keeper.altinity.com/v1"
"github.com/altinity/clickhouse-operator/pkg/chop/choptest"
)

const testShardKey = choptest.ShardLabelKey

var setWatchLabelSelector = choptest.SetWatchLabelSelector

func newLabeledCHK(labels map[string]string) *api.ClickHouseKeeperInstallation {
return &api.ClickHouseKeeperInstallation{
ObjectMeta: meta.ObjectMeta{
Namespace: "clickhouse",
Name: "test-chk",
Labels: labels,
},
}
}

func Test_keeperPredicateWithLabelSelector(t *testing.T) {
tests := []struct {
name string
selector string
labels map[string]string
want bool
}{
{"shard operator passes matching CHK", testShardKey + "=stg", map[string]string{testShardKey: "stg"}, true},
{"shard operator filters other shard's CHK", testShardKey + "=stg", map[string]string{testShardKey: "logs"}, false},
{"shard operator filters unlabeled CHK", testShardKey + "=stg", nil, false},
{"legacy operator passes unlabeled CHK", "!" + testShardKey, nil, true},
{"legacy operator filters shard-labeled CHK", "!" + testShardKey, map[string]string{testShardKey: "stg"}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
setWatchLabelSelector(t, tt.selector)
predicate := keeperPredicate()
chk := newLabeledCHK(tt.labels)

if got := predicate.Create(event.CreateEvent{Object: chk}); got != tt.want {
t.Errorf("keeperPredicate.Create() = %v, want %v", got, tt.want)
}
if got := predicate.Update(event.UpdateEvent{ObjectNew: chk}); got != tt.want {
t.Errorf("keeperPredicate.Update() = %v, want %v", got, tt.want)
}
})
}
}

// A label flip arrives at both operators as a plain Update: the losing operator filters it
// (no delete flow), the gaining operator processes it as a normal reconcile.
func Test_keeperLabelFlipIsNotDelete(t *testing.T) {
oldCHK := newLabeledCHK(nil)
newCHK := newLabeledCHK(map[string]string{testShardKey: "stg"})

t.Run("losing operator filters the flip update", func(t *testing.T) {
setWatchLabelSelector(t, "!"+testShardKey)
if keeperPredicate().Update(event.UpdateEvent{ObjectOld: oldCHK, ObjectNew: newCHK}) {
t.Error("operator losing a CHK on label flip must filter the update")
}
})

t.Run("gaining operator processes the flip update", func(t *testing.T) {
setWatchLabelSelector(t, testShardKey+"=stg")
if !keeperPredicate().Update(event.UpdateEvent{ObjectOld: oldCHK, ObjectNew: newCHK}) {
t.Error("operator gaining a CHK on label flip must process the update")
}
})
}
15 changes: 15 additions & 0 deletions config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ watch:
include: []
exclude: []

# Restricts which CHI/CHK resources this operator manages (label selector syntax,
# e.g. "example.com/clickhouse-shard=logs" or "!example.com/clickhouse-shard"). Empty manages everything.
# Env var override: WATCH_LABEL_SELECTOR. Invalid selector aborts startup.
# Note: an empty env var does NOT clear a file-configured selector (same semantics
# as WATCH_NAMESPACES) — de-sharding requires a file config change.
# Every label key referenced by the selector is automatically appended to
# `label.exclude` below: ownership labels never propagate to child objects, so
# re-assigning a CR to another operator never restarts its pods.
labelSelector: ""

# When true, an empty labelSelector aborts startup. Set on sharded operator deployments
# so a lost/typo'd selector fails loudly instead of silently watching everything.
# Env var override: WATCH_LABEL_SELECTOR_REQUIRED.
requireLabelSelector: false

# Behavior when ClickHouseOperatorConfiguration changes: none | restart
configuration:
onChange: restart
Expand Down
15 changes: 15 additions & 0 deletions deploy/builder/templates-config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ watch:
include: [${WATCH_NAMESPACES}]
exclude: []

# Restricts which CHI/CHK resources this operator manages (label selector syntax,
# e.g. "example.com/clickhouse-shard=logs" or "!example.com/clickhouse-shard"). Empty manages everything.
# Env var override: WATCH_LABEL_SELECTOR. Invalid selector aborts startup.
# Note: an empty env var does NOT clear a file-configured selector (same semantics
# as WATCH_NAMESPACES) — de-sharding requires a file config change.
# Every label key referenced by the selector is automatically appended to
# `label.exclude` below: ownership labels never propagate to child objects, so
# re-assigning a CR to another operator never restarts its pods.
labelSelector: ""

# When true, an empty labelSelector aborts startup. Set on sharded operator deployments
# so a lost/typo'd selector fails loudly instead of silently watching everything.
# Env var override: WATCH_LABEL_SELECTOR_REQUIRED.
requireLabelSelector: false

# Behavior when ClickHouseOperatorConfiguration changes: none | restart
configuration:
onChange: restart
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ spec:
type: object
description: "List of namespaces where clickhouse-operator watches for events."
x-kubernetes-preserve-unknown-fields: true
labelSelector:
type: string
description: "Label selector (standard Kubernetes label selector syntax) restricting which CHI/CHK resources this operator instance manages. Empty selector manages everything. Env var override: WATCH_LABEL_SELECTOR."
requireLabelSelector:
type: boolean
description: "When true, an empty labelSelector aborts operator startup. Env var override: WATCH_LABEL_SELECTOR_REQUIRED."
configuration:
type: object
description: "Behavior when ClickHouseOperatorConfiguration resources change"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ spec:
type: object
description: "List of namespaces where clickhouse-operator watches for events."
x-kubernetes-preserve-unknown-fields: true
labelSelector:
type: string
description: "Label selector (standard Kubernetes label selector syntax) restricting which CHI/CHK resources this operator instance manages. Empty selector manages everything. Env var override: WATCH_LABEL_SELECTOR."
requireLabelSelector:
type: boolean
description: "When true, an empty labelSelector aborts operator startup. Env var override: WATCH_LABEL_SELECTOR_REQUIRED."
configuration:
type: object
description: "Behavior when ClickHouseOperatorConfiguration resources change"
Expand Down
6 changes: 6 additions & 0 deletions deploy/helm/clickhouse-operator/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,12 @@
"namespaces": {
"type": ["array", "object"]
},
"labelSelector": {
"type": "string"
},
"requireLabelSelector": {
"type": "boolean"
},
"configuration": {
"type": "object",
"properties": {
Expand Down
13 changes: 13 additions & 0 deletions deploy/helm/clickhouse-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,19 @@ configs:
namespaces:
include: []
exclude: []
# Restricts which CHI/CHK resources this operator manages (label selector syntax,
# e.g. "example.com/clickhouse-shard=logs" or "!example.com/clickhouse-shard"). Empty manages everything.
# Env var override: WATCH_LABEL_SELECTOR. Invalid selector aborts startup.
# Note: an empty env var does NOT clear a file-configured selector (same semantics
# as WATCH_NAMESPACES) — de-sharding requires a file config change.
# Every label key referenced by the selector is automatically appended to
# `label.exclude` below: ownership labels never propagate to child objects, so
# re-assigning a CR to another operator never restarts its pods.
labelSelector: ""
# When true, an empty labelSelector aborts startup. Set on sharded operator deployments
# so a lost/typo'd selector fails loudly instead of silently watching everything.
# Env var override: WATCH_LABEL_SELECTOR_REQUIRED.
requireLabelSelector: false
# Behavior when ClickHouseOperatorConfiguration changes: none | restart
configuration:
onChange: restart
Expand Down
21 changes: 21 additions & 0 deletions deploy/operator/clickhouse-operator-install-ansible.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3769,6 +3769,12 @@ spec:
type: object
description: "List of namespaces where clickhouse-operator watches for events."
x-kubernetes-preserve-unknown-fields: true
labelSelector:
type: string
description: "Label selector (standard Kubernetes label selector syntax) restricting which CHI/CHK resources this operator instance manages. Empty selector manages everything. Env var override: WATCH_LABEL_SELECTOR."
requireLabelSelector:
type: boolean
description: "When true, an empty labelSelector aborts operator startup. Env var override: WATCH_LABEL_SELECTOR_REQUIRED."
configuration:
type: object
description: "Behavior when ClickHouseOperatorConfiguration resources change"
Expand Down Expand Up @@ -5720,6 +5726,21 @@ data:
include: [{{ namespace }}]
exclude: []

# Restricts which CHI/CHK resources this operator manages (label selector syntax,
# e.g. "example.com/clickhouse-shard=logs" or "!example.com/clickhouse-shard"). Empty manages everything.
# Env var override: WATCH_LABEL_SELECTOR. Invalid selector aborts startup.
# Note: an empty env var does NOT clear a file-configured selector (same semantics
# as WATCH_NAMESPACES) — de-sharding requires a file config change.
# Every label key referenced by the selector is automatically appended to
# `label.exclude` below: ownership labels never propagate to child objects, so
# re-assigning a CR to another operator never restarts its pods.
labelSelector: ""

# When true, an empty labelSelector aborts startup. Set on sharded operator deployments
# so a lost/typo'd selector fails loudly instead of silently watching everything.
# Env var override: WATCH_LABEL_SELECTOR_REQUIRED.
requireLabelSelector: false

# Behavior when ClickHouseOperatorConfiguration changes: none | restart
configuration:
onChange: restart
Expand Down
21 changes: 21 additions & 0 deletions deploy/operator/clickhouse-operator-install-bundle-v1beta1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3736,6 +3736,12 @@ spec:
type: object
description: "List of namespaces where clickhouse-operator watches for events."
x-kubernetes-preserve-unknown-fields: true
labelSelector:
type: string
description: "Label selector (standard Kubernetes label selector syntax) restricting which CHI/CHK resources this operator instance manages. Empty selector manages everything. Env var override: WATCH_LABEL_SELECTOR."
requireLabelSelector:
type: boolean
description: "When true, an empty labelSelector aborts operator startup. Env var override: WATCH_LABEL_SELECTOR_REQUIRED."
configuration:
type: object
description: "Behavior when ClickHouseOperatorConfiguration resources change"
Expand Down Expand Up @@ -5919,6 +5925,21 @@ data:
include: []
exclude: []

# Restricts which CHI/CHK resources this operator manages (label selector syntax,
# e.g. "example.com/clickhouse-shard=logs" or "!example.com/clickhouse-shard"). Empty manages everything.
# Env var override: WATCH_LABEL_SELECTOR. Invalid selector aborts startup.
# Note: an empty env var does NOT clear a file-configured selector (same semantics
# as WATCH_NAMESPACES) — de-sharding requires a file config change.
# Every label key referenced by the selector is automatically appended to
# `label.exclude` below: ownership labels never propagate to child objects, so
# re-assigning a CR to another operator never restarts its pods.
labelSelector: ""

# When true, an empty labelSelector aborts startup. Set on sharded operator deployments
# so a lost/typo'd selector fails loudly instead of silently watching everything.
# Env var override: WATCH_LABEL_SELECTOR_REQUIRED.
requireLabelSelector: false

# Behavior when ClickHouseOperatorConfiguration changes: none | restart
configuration:
onChange: restart
Expand Down
21 changes: 21 additions & 0 deletions deploy/operator/clickhouse-operator-install-bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3762,6 +3762,12 @@ spec:
type: object
description: "List of namespaces where clickhouse-operator watches for events."
x-kubernetes-preserve-unknown-fields: true
labelSelector:
type: string
description: "Label selector (standard Kubernetes label selector syntax) restricting which CHI/CHK resources this operator instance manages. Empty selector manages everything. Env var override: WATCH_LABEL_SELECTOR."
requireLabelSelector:
type: boolean
description: "When true, an empty labelSelector aborts operator startup. Env var override: WATCH_LABEL_SELECTOR_REQUIRED."
configuration:
type: object
description: "Behavior when ClickHouseOperatorConfiguration resources change"
Expand Down Expand Up @@ -5979,6 +5985,21 @@ data:
include: []
exclude: []

# Restricts which CHI/CHK resources this operator manages (label selector syntax,
# e.g. "example.com/clickhouse-shard=logs" or "!example.com/clickhouse-shard"). Empty manages everything.
# Env var override: WATCH_LABEL_SELECTOR. Invalid selector aborts startup.
# Note: an empty env var does NOT clear a file-configured selector (same semantics
# as WATCH_NAMESPACES) — de-sharding requires a file config change.
# Every label key referenced by the selector is automatically appended to
# `label.exclude` below: ownership labels never propagate to child objects, so
# re-assigning a CR to another operator never restarts its pods.
labelSelector: ""

# When true, an empty labelSelector aborts startup. Set on sharded operator deployments
# so a lost/typo'd selector fails loudly instead of silently watching everything.
# Env var override: WATCH_LABEL_SELECTOR_REQUIRED.
requireLabelSelector: false

# Behavior when ClickHouseOperatorConfiguration changes: none | restart
configuration:
onChange: restart
Expand Down
21 changes: 21 additions & 0 deletions deploy/operator/clickhouse-operator-install-template-v1beta1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3736,6 +3736,12 @@ spec:
type: object
description: "List of namespaces where clickhouse-operator watches for events."
x-kubernetes-preserve-unknown-fields: true
labelSelector:
type: string
description: "Label selector (standard Kubernetes label selector syntax) restricting which CHI/CHK resources this operator instance manages. Empty selector manages everything. Env var override: WATCH_LABEL_SELECTOR."
requireLabelSelector:
type: boolean
description: "When true, an empty labelSelector aborts operator startup. Env var override: WATCH_LABEL_SELECTOR_REQUIRED."
configuration:
type: object
description: "Behavior when ClickHouseOperatorConfiguration resources change"
Expand Down Expand Up @@ -5666,6 +5672,21 @@ data:
include: []
exclude: []

# Restricts which CHI/CHK resources this operator manages (label selector syntax,
# e.g. "example.com/clickhouse-shard=logs" or "!example.com/clickhouse-shard"). Empty manages everything.
# Env var override: WATCH_LABEL_SELECTOR. Invalid selector aborts startup.
# Note: an empty env var does NOT clear a file-configured selector (same semantics
# as WATCH_NAMESPACES) — de-sharding requires a file config change.
# Every label key referenced by the selector is automatically appended to
# `label.exclude` below: ownership labels never propagate to child objects, so
# re-assigning a CR to another operator never restarts its pods.
labelSelector: ""

# When true, an empty labelSelector aborts startup. Set on sharded operator deployments
# so a lost/typo'd selector fails loudly instead of silently watching everything.
# Env var override: WATCH_LABEL_SELECTOR_REQUIRED.
requireLabelSelector: false

# Behavior when ClickHouseOperatorConfiguration changes: none | restart
configuration:
onChange: restart
Expand Down
21 changes: 21 additions & 0 deletions deploy/operator/clickhouse-operator-install-template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3762,6 +3762,12 @@ spec:
type: object
description: "List of namespaces where clickhouse-operator watches for events."
x-kubernetes-preserve-unknown-fields: true
labelSelector:
type: string
description: "Label selector (standard Kubernetes label selector syntax) restricting which CHI/CHK resources this operator instance manages. Empty selector manages everything. Env var override: WATCH_LABEL_SELECTOR."
requireLabelSelector:
type: boolean
description: "When true, an empty labelSelector aborts operator startup. Env var override: WATCH_LABEL_SELECTOR_REQUIRED."
configuration:
type: object
description: "Behavior when ClickHouseOperatorConfiguration resources change"
Expand Down Expand Up @@ -5713,6 +5719,21 @@ data:
include: []
exclude: []

# Restricts which CHI/CHK resources this operator manages (label selector syntax,
# e.g. "example.com/clickhouse-shard=logs" or "!example.com/clickhouse-shard"). Empty manages everything.
# Env var override: WATCH_LABEL_SELECTOR. Invalid selector aborts startup.
# Note: an empty env var does NOT clear a file-configured selector (same semantics
# as WATCH_NAMESPACES) — de-sharding requires a file config change.
# Every label key referenced by the selector is automatically appended to
# `label.exclude` below: ownership labels never propagate to child objects, so
# re-assigning a CR to another operator never restarts its pods.
labelSelector: ""

# When true, an empty labelSelector aborts startup. Set on sharded operator deployments
# so a lost/typo'd selector fails loudly instead of silently watching everything.
# Env var override: WATCH_LABEL_SELECTOR_REQUIRED.
requireLabelSelector: false

# Behavior when ClickHouseOperatorConfiguration changes: none | restart
configuration:
onChange: restart
Expand Down
Loading
Loading