NO-ISSUE: Fix storage unit test panic#6751
Conversation
yaml.Unmarshal can set the Lvmd pointer to nil when the file is empty (e.g. read during concurrent truncation by the config watcher). This caused a nil pointer dereference panic at l.SocketName. Return an error instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
os.WriteFile with O_TRUNC can produce spurious IN_DELETE inotify events on Linux. The watcher would treat these as real deletions and fall back to default config, overwriting the user's config. Verify the file is actually gone before falling back to defaults; if it still exists, re-apply the user config. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The test used a 50ms time.Sleep to wait for the fsnotify watcher to process events, which was unreliable on loaded CI nodes. Replace with: - waitForRuntimeCfg: polls until runtime config matches expected value (5s timeout), used for positive assertions where a change is expected. - readRuntimeCfgAfterSettle: waits 500ms then reads, used for negative assertions where nothing should change (chmod, shutdown tests). Confirmed stable over 100 consecutive runs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@pmtk: This pull request explicitly references no jira issue. DetailsIn response to this: Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
WalkthroughThe PR improves lvmd configuration robustness by: validating that config YAML parses to a non-nil struct, making file-watch remove-event handling check file existence before defaulting, and refactoring watch tests to poll for expected state instead of using fixed delays. ChangesLVMD Config Robustness
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested labels
🚥 Pre-merge checks | ✅ 15✅ Passed checks (15 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=warning msg="The linter 'gomodguard' is deprecated (since v2.12.0) due to: new major version. Replaced by gomodguard_v2." ... [truncated 31032 characters] ... elet: is replaced in go.mod, but not marked as replaced in vendor/modules.txt\n\tk8s.io/metrics: is replaced in go.mod, but not marked as replaced in vendor/modules.txt\n\tk8s.io/mount-utils: is replaced in go.mod, but not marked as replaced in vendor/modules.txt\n\tk8s.io/pod-security-admission: is replaced in go.mod, but not marked as replaced in vendor/modules.txt\n\tk8s.io/sample-apiserver: is replaced in go.mod, but not marked as replaced in vendor/modules.txt\n\tk8s.io/sample-cli-plugin: is replaced in go.mod, but not marked as replaced in vendor/modules.txt\n\tk8s.io/sample-controller: is replaced in go.mod, but not marked as replaced in vendor/modules.txt\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor\n" Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pkg/config/lvmd/lvmd.go (1)
40-46:⚠️ Potential issue | 🔴 CriticalFix
yaml.Unmarshal(buf, &l)toyaml.Unmarshal(buf, l)and make the “empty file” check actually work
l := new(Lvmd)already yields a non-nil*Lvmd; passing&lgives**Lvmd, and the subsequentif l == nilcheck won’t reliably trigger on empty YAML, so empty lvmd files may be treated as successfully parsed. Useyaml.Unmarshal(buf, l)and detect empty input viabuf(or validate required fields) rather than relying on the pointer being nilled by unmarshal.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/config/lvmd/lvmd.go` around lines 40 - 46, The current code passes &l to yaml.Unmarshal and then checks if l == nil, which is wrong because l is created via l := new(Lvmd) (a non-nil *Lvmd) and &l yields **Lvmd; change the Unmarshal call to yaml.Unmarshal(buf, l) to pass the *Lvmd, and replace the ineffective nil check with a real empty-file/validation check — for example, return an error if len(buf) == 0 or validate required fields on the Lvmd struct (e.g., requiredName/ID fields) after unmarshalling; update error messages accordingly to reference the lvmd file path p and the failing validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@pkg/config/lvmd/lvmd.go`:
- Around line 40-46: The current code passes &l to yaml.Unmarshal and then
checks if l == nil, which is wrong because l is created via l := new(Lvmd) (a
non-nil *Lvmd) and &l yields **Lvmd; change the Unmarshal call to
yaml.Unmarshal(buf, l) to pass the *Lvmd, and replace the ineffective nil check
with a real empty-file/validation check — for example, return an error if
len(buf) == 0 or validate required fields on the Lvmd struct (e.g.,
requiredName/ID fields) after unmarshalling; update error messages accordingly
to reference the lvmd file path p and the failing validation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Central YAML (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: 4cfdf85a-a192-46f3-ba53-729c97891d06
📒 Files selected for processing (3)
pkg/components/storage.gopkg/components/storage_test.gopkg/config/lvmd/lvmd.go
The finding is incorrect. yaml.Unmarshal(buf, &l) where l is *Lvmd passes a **Lvmd, which allows the unmarshaller to set the pointer to nil on empty input. This is the intended behavior — the if l == nil check works correctly. Empirical verification: package main
import (
"fmt"
"sigs.k8s.io/yaml"
)
type Lvmd struct {
SocketName string `json:"socketName"`
}
func main() {
l := new(Lvmd)
fmt.Printf("before: l=%p, *l=%+v\n", l, *l)
err := yaml.Unmarshal([]byte(""), &l)
fmt.Printf("after empty unmarshal: l=%v, err=%v\n", l, err)
l2 := new(Lvmd)
err = yaml.Unmarshal([]byte("---\n"), &l2)
fmt.Printf("after '---' unmarshal: l2=%v, err=%v\n", l2, err)
l3 := new(Lvmd)
err = yaml.Unmarshal(nil, &l3)
fmt.Printf("after nil unmarshal: l3=%v, err=%v\n", l3, err)
}Output: Changing to yaml.Unmarshal(buf, l) as suggested would break the nil check — the unmarshaller would write into the existing struct and l would never be nil. |
|
/test ? |
|
/test e2e-aws-tests-bootc-periodic-arm-el9 e2e-aws-tests-bootc-periodic-el10 |
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: ggiguash, pmtk The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/verified by ci |
|
@copejon: This PR has been marked as verified by DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
@pmtk: all tests passed! Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
Summary by CodeRabbit