Skip to content

Commit b238283

Browse files
authored
[addon-operator] Backport 1.15: fix readiness bug (#706)
Signed-off-by: Timur Tuktamyshev <[email protected]>
1 parent c79b1f0 commit b238283

File tree

2 files changed

+71
-24
lines changed

2 files changed

+71
-24
lines changed

pkg/module_manager/models/modules/basic.go

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -238,21 +238,22 @@ func (bm *BasicModule) ResetState() {
238238
bm.l.Unlock()
239239
}
240240

241+
// RegisterHooks searches and registers all module hooks from a filesystem or GoHook Registry
241242
// RegisterHooks searches and registers all module hooks from a filesystem or GoHook Registry
242243
func (bm *BasicModule) RegisterHooks(logger *log.Logger) ([]*hooks.ModuleHook, error) {
243244
if bm.hooks.registered {
244245
logger.Debug("Module hooks already registered")
245246
return nil, nil
246247
}
247248

248-
hks, err := bm.searchModuleHooks()
249+
searchModuleHooksResult, err := bm.searchModuleHooks()
249250
if err != nil {
250251
return nil, fmt.Errorf("search module hooks failed: %w", err)
251252
}
252253

253-
logger.Debug("Found hooks", slog.Int("count", len(hks)))
254+
logger.Debug("Found hooks", slog.Int("count", len(searchModuleHooksResult.Hooks)))
254255
if logger.GetLevel() == log.LevelDebug {
255-
for _, h := range hks {
256+
for _, h := range searchModuleHooksResult.Hooks {
256257
logger.Debug("ModuleHook",
257258
slog.String("name", h.GetName()),
258259
slog.String("path", h.GetPath()))
@@ -261,56 +262,65 @@ func (bm *BasicModule) RegisterHooks(logger *log.Logger) ([]*hooks.ModuleHook, e
261262

262263
logger.Debug("Register hooks")
263264

264-
if err := bm.registerHooks(hks, logger); err != nil {
265+
if err := bm.registerHooks(searchModuleHooksResult.Hooks, logger); err != nil {
265266
return nil, fmt.Errorf("register hooks: %w", err)
266267
}
267268

268269
bm.hooks.registered = true
270+
bm.hasReadiness = searchModuleHooksResult.HasReadiness
269271

270-
return hks, nil
272+
return searchModuleHooksResult.Hooks, nil
273+
}
274+
275+
type searchModuleHooksResult struct {
276+
Hooks []*hooks.ModuleHook
277+
HasReadiness bool
271278
}
272279

273-
func (bm *BasicModule) searchModuleHooks() ([]*hooks.ModuleHook, error) {
280+
func (bm *BasicModule) searchModuleHooks() (*searchModuleHooksResult, error) {
274281
shellHooks, err := bm.searchModuleShellHooks()
275282
if err != nil {
276283
return nil, fmt.Errorf("search module shell hooks: %w", err)
277284
}
278285

279286
goHooks := bm.searchModuleGoHooks()
280287

281-
batchHooks, err := bm.searchModuleBatchHooks()
288+
batchHooksResult, err := bm.searchModuleBatchHooks()
282289
if err != nil {
283290
return nil, fmt.Errorf("search module batch hooks: %w", err)
284291
}
285292

286-
if len(shellHooks)+len(batchHooks) > 0 {
293+
if len(shellHooks)+len(batchHooksResult.Hooks) > 0 {
287294
if err := bm.AssembleEnvironmentForModule(environmentmanager.ShellHookEnvironment); err != nil {
288295
return nil, fmt.Errorf("Assemble %q module's environment: %w", bm.GetName(), err)
289296
}
290297
}
291298

292-
mHooks := make([]*hooks.ModuleHook, 0, len(shellHooks)+len(goHooks))
299+
result := &searchModuleHooksResult{
300+
Hooks: make([]*hooks.ModuleHook, 0, len(shellHooks)+len(goHooks)+len(batchHooksResult.Hooks)),
301+
HasReadiness: batchHooksResult.HasReadiness,
302+
}
293303

294304
for _, sh := range shellHooks {
295305
mh := hooks.NewModuleHook(sh)
296-
mHooks = append(mHooks, mh)
306+
result.Hooks = append(result.Hooks, mh)
297307
}
298308

299309
for _, gh := range goHooks {
300310
mh := hooks.NewModuleHook(gh)
301-
mHooks = append(mHooks, mh)
311+
result.Hooks = append(result.Hooks, mh)
302312
}
303313

304-
for _, bh := range batchHooks {
314+
for _, bh := range batchHooksResult.Hooks {
305315
mh := hooks.NewModuleHook(bh)
306-
mHooks = append(mHooks, mh)
316+
result.Hooks = append(result.Hooks, mh)
307317
}
308318

309-
sort.SliceStable(mHooks, func(i, j int) bool {
310-
return mHooks[i].GetPath() < mHooks[j].GetPath()
319+
sort.SliceStable(result.Hooks, func(i, j int) bool {
320+
return result.Hooks[i].GetPath() < result.Hooks[j].GetPath()
311321
})
312322

313-
return mHooks, nil
323+
return result, nil
314324
}
315325

316326
func (bm *BasicModule) searchModuleShellHooks() ([]*kind.ShellHook, error) {
@@ -372,18 +382,31 @@ func (bm *BasicModule) searchModuleShellHooks() ([]*kind.ShellHook, error) {
372382
return hks, nil
373383
}
374384

375-
func (bm *BasicModule) searchModuleBatchHooks() ([]*kind.BatchHook, error) {
385+
// searchModuleBatchHooks searches for batch hooks and returns them along with hasReadiness flag.
386+
// This function has no side effects - it doesn't modify bm.hasReadiness directly.
387+
// The caller (RegisterHooks) is responsible for setting bm.hasReadiness after successful registration.
388+
type searchModuleBatchHooksResult struct {
389+
Hooks []*kind.BatchHook
390+
HasReadiness bool
391+
}
392+
393+
// searchModuleBatchHooks searches for batch hooks and returns them along with hasReadiness flag.
394+
// This function has no side effects - it doesn't modify bm.hasReadiness directly.
395+
// The caller (RegisterHooks) is responsible for setting bm.hasReadiness after successful registration.
396+
func (bm *BasicModule) searchModuleBatchHooks() (*searchModuleBatchHooksResult, error) {
376397
hooksDir := filepath.Join(bm.Path, "hooks")
377398
if _, err := os.Stat(hooksDir); os.IsNotExist(err) {
378-
return nil, nil
399+
return &searchModuleBatchHooksResult{}, nil
379400
}
380401

381402
hooksRelativePaths, err := RecursiveGetBatchHookExecutablePaths(bm.safeName(), hooksDir, bm.logger, hooksExcludedDir...)
382403
if err != nil {
383404
return nil, err
384405
}
385406

386-
hks := make([]*kind.BatchHook, 0)
407+
result := &searchModuleBatchHooksResult{
408+
Hooks: make([]*kind.BatchHook, 0, len(hooksRelativePaths)),
409+
}
387410

388411
// sort hooks by path
389412
sort.Strings(hooksRelativePaths)
@@ -401,27 +424,27 @@ func (bm *BasicModule) searchModuleBatchHooks() ([]*kind.BatchHook, error) {
401424
}
402425

403426
if sdkcfgs.Readiness != nil {
404-
if bm.hasReadiness {
427+
if result.HasReadiness {
405428
return nil, fmt.Errorf("multiple readiness hooks found in %s", hookPath)
406429
}
407430

408-
bm.hasReadiness = true
431+
result.HasReadiness = true
409432

410433
// add readiness hook
411434
nestedHookName := fmt.Sprintf("%s-readiness", hookName)
412435
shHook := kind.NewBatchHook(nestedHookName, hookPath, bm.safeName(), kind.BatchHookReadyKey, bm.keepTemporaryHookFiles, shapp.LogProxyHookJSON, bm.logger.Named("batch-hook"))
413-
hks = append(hks, shHook)
436+
result.Hooks = append(result.Hooks, shHook)
414437
}
415438

416439
for key, cfg := range sdkcfgs.Hooks {
417440
nestedHookName := fmt.Sprintf("%s:%s:%s", hookName, cfg.Metadata.Name, key)
418441
shHook := kind.NewBatchHook(nestedHookName, hookPath, bm.safeName(), key, bm.keepTemporaryHookFiles, shapp.LogProxyHookJSON, bm.logger.Named("batch-hook"))
419442

420-
hks = append(hks, shHook)
443+
result.Hooks = append(result.Hooks, shHook)
421444
}
422445
}
423446

424-
return hks, nil
447+
return result, nil
425448
}
426449

427450
func RecursiveGetBatchHookExecutablePaths(moduleName, dir string, logger *log.Logger, excludedDirs ...string) ([]string, error) {

pkg/module_manager/models/modules/basic_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,27 @@ exit 0
309309
require.NotNil(t, erGetter)
310310
require.Equal(t, "Kubernetes version is too low", *erGetter)
311311
}
312+
313+
// TestHasReadinessNotSetOnFailedRegistration tests that hasReadiness is only set
314+
// after successful hook registration. This prevents stale hasReadiness state when
315+
// registration is retried after an error (e.g., in AssembleEnvironmentForModule).
316+
func TestHasReadinessNotSetOnFailedRegistration(t *testing.T) {
317+
tmpModuleDir := t.TempDir()
318+
319+
bm, err := NewBasicModule("test-readiness-registration", tmpModuleDir, 1, utils.Values{}, nil, nil)
320+
require.NoError(t, err)
321+
322+
logger := log.NewLogger()
323+
bm.WithLogger(logger)
324+
bm.WithDependencies(stubDeps(logger))
325+
326+
// Simulate stale state from a previous failed registration attempt
327+
bm.hasReadiness = true
328+
329+
// RegisterHooks should overwrite hasReadiness based on actual search results
330+
_, err = bm.RegisterHooks(logger)
331+
require.NoError(t, err)
332+
333+
// hasReadiness should be false (no hooks in empty module)
334+
require.False(t, bm.hasReadiness, "hasReadiness should reflect actual hooks found")
335+
}

0 commit comments

Comments
 (0)