-
Notifications
You must be signed in to change notification settings - Fork 1.8k
[configoptional] Validate nested types #13611
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[configoptional] Validate nested types #13611
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. ❌ Your project status has failed because the head coverage (87.65%) is below the target coverage (90.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #13611 +/- ##
==========================================
- Coverage 87.67% 87.65% -0.03%
==========================================
Files 632 632
Lines 39697 39709 +12
==========================================
Hits 34806 34806
- Misses 3648 3657 +9
- Partials 1243 1246 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
This will fix the underlying issue in #13580. The test changes there would be nice to keep. @evan-bradley feel free to copy just the exporter/exporterhelper/internal/queuebatch/config_test.go portion to add testing here. |
bogdandrutu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we depend on xconfmap everywhere because of this, or should we do xconfmap depend of optional, and there check if a public field is "ConfigOptional" and if it is get the value.
I like more to have xconfmap depend on configoptional, but want to hear others.
I would still prefer to have configoptional -> (x)confmap:
|
|
Thanks everyone for the quick reviews. I'm okay making this a bug fix, though I think we should consider making changelogs for affected components since configoptional is probably something most users aren't familiar with. I'll add and fix tests for the exporter helper in a follow up to this PR. I've also updated this PR to include a few tests to check a few different cases. @jade-guiton-dd following up on our conversation during the 2025-08-11 stability call, I've still elected to continue to validate the default flavor of the Optional type. I think we want to make it easier for component authors to catch that their defaults aren't considered valid configuration without requiring them to call |
Makes sense to me to do this.
I agree with this decision, also because it is easier to start validating it and stop doing it in the future than the other way around (since we would potentially break people's configs). @jade-guiton-dd What do you think? |
I'm sorry, I don't understand this paragraph at all. What does Unmarshal have to do with validation? And how would a user be able to bypass the Validate check if the default not being valid is intentional?
Technically, this PR would already break people's configs compared to the previous system (pointer-based optional fields). If you had a very simple otlpreceiver-like config like this: type MyConfig struct {
GRPC *configgrpc.ServerConfig `mapstructure:"grpc"`
}
func (cfg *MyConfig) Unmarshal(conf *confmap.Conf) error {
err := conf.Unmarshal(cfg)
if err != nil {
return err
}
if !conf.IsSet("grpc") {
cfg.GRPC = nil
}
}
func createDefaultConfig() component.Config {
return &MyConfig{
GRPC: configgrpc.NewDefaultServerConfig(),
}
}
If you don't set a Now updated to use configoptional: type MyConfig struct {
GRPC configoptional.Optional[configgrpc.ServerConfig] `mapstructure:"grpc"`
}
// No need for Unmarshal, great!
func createDefaultConfig() component.Config {
return &MyConfig{
GRPC: configoptional.Default(configgrpc.NewDefaultServerConfig()),
}
}With the current state of this PR, you would now get validation errors about And importantly: I don't see any way with this PR that a component author could bypass these validation errors if the intent was to make those fields required. The only reason this PR would only "technically" cause breakage is because the only known user of I think this PR only makes sense if we decide to more formally create a rule that any config struct (even substructs like |
|
@jade-guiton-dd appreciate your thoughts here, thanks for all the details.
Argh, I forgot to check for this. You're right, we don't want this behavior. I missed this in my testing, I've added a test that covers this now. The fact that all tests passed in this PR also indicates to me we lack tests around this elsewhere in the repo, so I will issue a few pre-req PRs to make sure we have this covered. @mx-psi I had to go the other route on validating default values due to this behavior. It makes testing slightly harder for component authors, but is necessary since the
Sorry, maybe I could have made that a bit clearer. Calling For your second question, my intent was that the user wouldn't come into play for this consideration and it would just be a way for component authors to be explicit about requiring certain fields inside optional config objects. |
That was my point: because of low adoption this would not break almost anybody today. And then if we end up facing the case you mention (e.g. in contrib) then we can remove the default validation.
But I see your point here and that's fair. I don't think we need to commit to anything specific but it does feel weird to do this. |
|
Both of the contrib test failures are expected and will be fixed in a follow-up PR after this one is merged. |
jade-guiton-dd
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic looks good to me. I find the tests a bit confusing, but I won't block merging on that.
| return nil | ||
| } | ||
|
|
||
| func TestOptionalFileValidate(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this test a bit confusing. The test struct is pretty convoluted and tests multiple things at once, so it's not easy to convince myself that the test is correct and covers all the cases we care about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair. I've been erring on the side of testing too many things for this PR, but if it weakens the signal that we've covered the cases we want, I'll pare it down some or at least explain why we're doing what we are.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reduced the struct size and made the test names more descriptive. The only excess now is the nested optional struct, which I left in there just to make sure we're properly calling xconfmap.Validate. Let me know if it looks better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a lot simpler to understand, thank you.
Maybe it would be worth it to add a test case for "invalid default + explicit", just in case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me, done.
| cfg.Sizer = request.SizerType{} | ||
| require.EqualError(t, xconfmap.Validate(cfg), "`batch` supports only `items` or `bytes` sizer") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
74d02da
The property `flush_timeout` has been required since v0.134.0. I believe this is a result of fixing config validation in open-telemetry/opentelemetry-collector#13611.
* chore: update OTel Collector libraries to `v1.41.0`/`v0.135.0` * fix(auditbeat): update ebpfevents to `v0.8.0` Resolves dependency conflict on github.com/cilium/ebpf. * make notice * test: fix TestFilebeatOTelE2E integration test The property `flush_timeout` has been required since v0.134.0. I believe this is a result of fixing config validation in open-telemetry/opentelemetry-collector#13611. * test: fix unit tests
* chore: update OTel Collector libraries to `v1.41.0`/`v0.135.0` * fix(auditbeat): update ebpfevents to `v0.8.0` Resolves dependency conflict on github.com/cilium/ebpf. * make notice * test: fix TestFilebeatOTelE2E integration test The property `flush_timeout` has been required since v0.134.0. I believe this is a result of fixing config validation in open-telemetry/opentelemetry-collector#13611. * test: fix unit tests (cherry picked from commit 16c4d9a) # Conflicts: # NOTICE.txt # go.mod # go.sum # x-pack/filebeat/tests/integration/otel_test.go # x-pack/metricbeat/tests/integration/otel_test.go
* chore: update OTel Collector libraries to `v1.41.0`/`v0.135.0` * fix(auditbeat): update ebpfevents to `v0.8.0` Resolves dependency conflict on github.com/cilium/ebpf. * make notice * test: fix TestFilebeatOTelE2E integration test The property `flush_timeout` has been required since v0.134.0. I believe this is a result of fixing config validation in open-telemetry/opentelemetry-collector#13611. * test: fix unit tests (cherry picked from commit 16c4d9a) # Conflicts: # NOTICE.txt # go.mod # go.sum
Description
The fact that
Optionalis a config type with private fields means it needs to manually continue thexconfmap.Validatecall chain using one of its private values, since the reflection calls inxconfmap.Validatecan't manually introspect them (and arguably shouldn't).Link to tracking issue
Fixes #13579