Skip to content
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

[otelcol] Obtain the Collector's effective configuration from otelcol.Config #10139

Merged
merged 7 commits into from
Jul 12, 2024

Conversation

evan-bradley
Copy link
Contributor

@evan-bradley evan-bradley commented May 10, 2024

Description

The otelcol.ConfmapProvider interface accurately reports the config provided to the Collector by the user, but fails to effectively report the Collector's effective configuration. In particular, it misses:

  • Default values for fields in Config structs.
  • Transformations done to Config structs by their Unmarshal or Validate methods.
  • Custom marshaling of types after we know the type of the config. This is most obvious with configopaque.String, where we want these values to always be redacted when sent out of the Collector.

I think we should attempt to get the Collector's effective configuration from otelcol.Config instead of using the map compiled by the confmap.Resolver. This also allows us to get rid of otelcol.ConfmapProvider.

I have manually tested this using an OpAMP Supervisor setup, but wasn't able to add unit tests due to the way otelcol.Collector is written.

@evan-bradley evan-bradley requested review from a team and jpkrohling May 10, 2024 21:21
@evan-bradley evan-bradley marked this pull request as draft May 10, 2024 21:21
@evan-bradley
Copy link
Contributor Author

To demonstrate the issue I'm seeing, this will fail:

cfg, _ := col.configProvider.Get(ctx, factories)
conf := confmap.New()
_ = conf.Marshal(cfg)
// This fails
bytes, err := yaml.Marshal(conf.ToStringMap())

This will succeed:

cfg, _ := col.configProvider.Get(ctx, factories)
// This succeeds
bytes, err := yaml.Marshal(cfg)

I'm fine just letting ConfigWatcher.NotifyConfig take an opaque any-typed parameter and telling the user to just marshal it with whatever format they want, but I don't fully understand why the first one fails. The second one also appears to make us more dependent on yaml since we don't have mapstructure as a buffer (e.g. we need to add yaml:"-" to confighttp.ClientConfig for the second snippet to work).

@sfc-gh-bdrutu
Copy link

As a result, I think we should attempt to get the Collector's effective configuration from otelcol.Config instead of using the map compiled by the confmap.Resolver. I initially intended to generate a confmap.Conf from otelcol.Config and call yaml.Marshal on that, but this encounters errors such as being unable to marshal Prometheus config which has invalid zero values. These errors don't occur when calling yaml.Marshal on otelcol.Config directly. I've updated and tested updating the ConfigWatcher interface to just accept an opaque any-typed data object and marshal that, and the end-to-end flow works. I haven't dug into this far enough to fully understand the differences between unmarshaling each type.

I think you should look into fixing marshal. /cc @atoulme

@evan-bradley
Copy link
Contributor Author

I think you should look into fixing marshal.

Thanks for the tip, I think that's also the best path forward. I found that the issue is that we don't do anything with yaml tags, which is what most third-party structs annotate on their fields. I will issue a PR to find a solution to that problem then update this PR afterward.

Copy link

codecov bot commented May 21, 2024

Codecov Report

Attention: Patch coverage is 33.33333% with 2 lines in your changes missing coverage. Please review.

Project coverage is 92.26%. Comparing base (08b0be7) to head (a708ac8).
Report is 1 commits behind head on main.

Files Patch % Lines
otelcol/collector.go 33.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #10139      +/-   ##
==========================================
- Coverage   92.35%   92.26%   -0.09%     
==========================================
  Files         395      395              
  Lines       18706    18703       -3     
==========================================
- Hits        17275    17257      -18     
- Misses       1070     1086      +16     
+ Partials      361      360       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@djaglowski
Copy link
Member

I think you should look into fixing marshal.

Thanks for the tip, I think that's also the best path forward. I found that the issue is that we don't do anything with yaml tags, which is what most third-party structs annotate on their fields. I will issue a PR to find a solution to that problem then update this PR afterward.

I have a possible solution in #10282.

Basically it adds a hook which looks for structs that have yaml tags but no mapstructure tags. For such structs, it uses the yaml package to "natively" convert the struct into map[string]any, which can then be marshaled by mapstructure in a generic way.

evan-bradley added a commit to open-telemetry/opentelemetry-collector-contrib that referenced this pull request Jun 3, 2024
**Description:** <Describe what has changed.>

Redacts primitive values in the effective config reported by the
extension.

Necessary for
#31641
until
open-telemetry/opentelemetry-collector#10139 is
resolved.

Relates to
#32983
codeboten pushed a commit that referenced this pull request Jun 17, 2024
Possible solution for
#10139 (comment)

More thorough explanation here:
#10139 (comment)

---------

Co-authored-by: Evan Bradley <11745660+evan-bradley@users.noreply.github.com>
Copy link
Contributor

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@mackjmr
Copy link
Member

mackjmr commented Jun 27, 2024

It seems like the ask to:

generate a confmap.Conf from otelcol.Config and call yaml.Marshal on that

cfg, _ := col.configProvider.Get(ctx, factories)
conf := confmap.New()
_ = conf.Marshal(cfg)
// This fails
bytes, err := yaml.Marshal(conf.ToStringMap())

is now supported following:

Are there any other scenarios where the code snippet above will fail ?

@evan-bradley
Copy link
Contributor Author

@mackjmr You're right, this will work now; thanks for keeping an eye on it. I haven't been able to get back to this, but I have more time now and will push an update this week.

@evan-bradley evan-bradley force-pushed the deprecate-confmapprovider branch 2 times, most recently from 0f70ae9 to aee771d Compare July 9, 2024 19:45
@evan-bradley evan-bradley marked this pull request as ready for review July 9, 2024 19:48
conf := confmap.New()

if err = conf.Marshal(cfg); err != nil {
return fmt.Errorf("could not marshal configuration: %w", err)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option could be to make this only a warning log, if we're comfortable that all extensions asking for the effective configuration will get an empty map.

otelcol/configprovider_test.go Outdated Show resolved Hide resolved
@@ -142,12 +144,3 @@ func (cm *configProvider) Watch() <-chan error {
func (cm *configProvider) Shutdown(ctx context.Context) error {
return cm.mapResolver.Shutdown(ctx)
}

func (cm *configProvider) GetConfmap(ctx context.Context) (*confmap.Conf, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep a dummy implementation of this method for one or more releases that returns an error saying that this functionality is deprecated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this because I don't expect anyone else is using it, but thinking on it, this should go through the normal deprecation process. I've added a deprecation notice to this method and we can just remove the implementation when we remove the interface. I would feel comfortable removing both one release after deprecating them.

@mx-psi mx-psi merged commit 3087c53 into open-telemetry:main Jul 12, 2024
49 of 50 checks passed
@github-actions github-actions bot added this to the next release milestone Jul 12, 2024
@yurishkuro
Copy link
Member

is this purely internal change, or can the end user print the config now?

@evan-bradley
Copy link
Contributor Author

This only affects the Collector APIs, but it is a step towards allowing the user to print the config.

evan-bradley added a commit to open-telemetry/opentelemetry-collector-contrib that referenced this pull request Jul 16, 2024
**Description:**

Now that
open-telemetry/opentelemetry-collector#10139 is
merged, we can rely on the Collector APIs to redact sensitive fields in
the config for us.

I tested this against the latest Collector core commit with the goal
that this will land in the v0.105.0 release.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants