Skip to content

Commit 741b1c3

Browse files
committed
Fix up configwatcher symlink re-creation (#1076)
* Fix up configwatcher symlink re-creation * Add changelog entries (cherry picked from commit da59ea5)
1 parent 1c00a87 commit 741b1c3

File tree

3 files changed

+28
-7
lines changed

3 files changed

+28
-7
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
project: charts/redpanda
2+
kind: Fixed
3+
body: 'Fix a bug with the way the config-watcher sidecar syncs users. The Kubernetes mechanism for writing out a changed secret is involves re-creating a symlink in the secrets directory that points to the mounted secret. Previously the config-watcher only detected changes to the entire directory and could potentially miss syncs, this resyncs everything anytime the symlink is recreated. '
4+
time: 2025-09-10T13:24:35.58267-04:00
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
project: operator
2+
kind: Fixed
3+
body: 'Fix a bug with the way the config-watcher sidecar syncs users. The Kubernetes mechanism for writing out a changed secret is involves re-creating a symlink in the secrets directory that points to the mounted secret. Previously the config-watcher only detected changes to the entire directory and could potentially miss syncs, this resyncs everything anytime the symlink is recreated. '
4+
time: 2025-09-10T13:24:35.582669-04:00

operator/internal/configwatcher/configwatcher.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,13 @@ type Option func(c *ConfigWatcher)
3939
// ConfigWatcher replaces the old bash scripts we leveraged for waiting
4040
// for a cluster to become stable and then creating superusers
4141
type ConfigWatcher struct {
42-
adminClient *rpadmin.AdminAPI
43-
configPath string
44-
usersDirectory string
45-
watch bool
46-
fs afero.Fs
47-
log logr.Logger
42+
adminClient *rpadmin.AdminAPI
43+
configPath string
44+
usersDirectory string
45+
defaultK8sUserSymlink string
46+
watch bool
47+
fs afero.Fs
48+
log logr.Logger
4849

4950
// When deployed using operator cluster configuration is synced only
5051
// in main reconciler. ConfigWatcher sidecar should only synchronize users
@@ -100,6 +101,7 @@ func NewConfigWatcher(log logr.Logger, watch bool, options ...Option) *ConfigWat
100101
for _, option := range options {
101102
option(watcher)
102103
}
104+
watcher.defaultK8sUserSymlink = path.Join(watcher.usersDirectory, "..data")
103105

104106
return watcher
105107
}
@@ -168,7 +170,18 @@ func (w *ConfigWatcher) watchFilesystem(ctx context.Context) error {
168170
w.log.Error(err, "watcher returned an error")
169171
time.Sleep(5 * time.Second)
170172
case event := <-watcher.Events:
171-
if strings.HasSuffix(event.Name, ".txt") {
173+
// Kubernete updates secrets by swapping a symlink named `..data`.
174+
// We must watch for the CREATE event on this specific symlink.
175+
if event.Name == w.defaultK8sUserSymlink && event.Has(fsnotify.Create) {
176+
w.log.Info("Kubernetes secret update detected, synchronizing users", "event", event.String())
177+
// use syncInital to re-read entire Directory
178+
w.syncInitial(ctx)
179+
continue
180+
}
181+
182+
// The original logic in case there is direct file writes,
183+
if event.Has(fsnotify.Write) && strings.HasSuffix(event.Name, ".txt") {
184+
w.log.Info("Direct file write detected, synchronizing users", "event", event.String())
172185
w.SyncUsers(ctx, event.Name)
173186
}
174187
case <-ctx.Done():

0 commit comments

Comments
 (0)