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

Add support in the confmap.Resolver to expand embedded config URIs inside configuration #4742

Merged
merged 1 commit into from
Aug 4, 2022

Conversation

bogdandrutu
Copy link
Member

@bogdandrutu bogdandrutu commented Jan 25, 2022

Proposal on how we can extend our current config provider to support expanding (including) config "parts". This will fix #4231 and will fully implement same capabilities as proposed in #4468.

This design is based on the https://docs.google.com/document/d/1XlDpS8-a4Ds6uoe6C6WgO8mCpDaQNufcHSEmBpiCdI0/edit format which we already support for the "--config" flag.

confmap.Provider changes

Extend the capability of a confmap.Provider to return a Provided value that can encapsulate a confmap.Conf or any partial config value (float64/int64/bool/string/map[string]interface{}/[]interface{} where map values or slice values have the same restrictions). The current design allows recursive expansions, so values returned by expanding one embedded config URI will be searched for expanding again.

Known caveats

  1. The proposed mechanism does not allow expanding values within other values, for example this case ${http://example.com/get_config?os=${env:OSNAME}} will NOT expand first the OSNAME env var.

Examples of usages

Retrieving token from zookeeper (scheme not yet defined)

exporters:
  signalfx:
    # this will read the access_token value from "zk" config provider.
    access_token: ${zk:zk1,zk2,zk2/path/to/data}

Retrieving an entire exporter config from a file

exporters:
  # this will read the entire config for the otlp/file exporter from the given file
  otlp/file_config: ${file:path/to/config/file/for/the/exporter.yaml}

Expanding env vars

exporters:
  otlp:
    endpoint: ${env:MY_ENV}

  otlp/backwards_compatible:
    endpoint: ${MY_ENV}

Expand Converter vs embedded config

The current proposal to support embedding config URIs, does not support the following cases that are supported by the expand envvar Converter:

  1. Using $ without brackets:
exporters:
  otlp/another_way_to_use_env_vars:
    endpoint: $MY_ENV
  1. Expanding values within a string value and concatenate:
exporters:
  otlp/localhost_enpoint:
    endpoint: "localhost:${OTLP_PORT_ENV}"

Because of these missing features the Expand Converter will be maintain for a period of time until a final decision between supporting or not the 2 missing features is made. If we decide to not support any of these features we can start at least by logging errors and disable the functionality behind a featuregate until we know if this is needed or not.

Signed-off-by: Bogdan Drutu [email protected]

@bogdandrutu

This comment was marked as outdated.

@bogdandrutu

This comment was marked as outdated.

@jpkrohling

This comment was marked as off-topic.

@jpkrohling

This comment was marked as outdated.

@jpkrohling

This comment was marked as outdated.

@bogdandrutu

This comment was marked as outdated.

Copy link
Contributor

@codeboten codeboten left a comment

Choose a reason for hiding this comment

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

I like where this functionality is going, I would love to hear from folks that are implementing downstream providers whether they have any concerns with this approach. To be clear this mean NewExpandConverter remains as the public API to use moving forward?

config/configmapprovider/expand.go Outdated Show resolved Hide resolved
config/configmapprovider/expand.go Outdated Show resolved Hide resolved
@tigrannajaryan

This comment was marked as resolved.

@Aneurysm9

This comment was marked as outdated.

@mx-psi

This comment was marked as resolved.

@bogdandrutu

This comment was marked as resolved.

@mx-psi

This comment was marked as outdated.

@github-actions
Copy link
Contributor

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

@github-actions
Copy link
Contributor

github-actions bot commented Mar 5, 2022

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

@github-actions
Copy link
Contributor

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

@bogdandrutu

This comment was marked as outdated.

@codecov
Copy link

codecov bot commented Apr 19, 2022

Codecov Report

Merging #4742 (3665334) into main (dc42194) will increase coverage by 0.16%.
The diff coverage is 99.03%.

@@            Coverage Diff             @@
##             main    #4742      +/-   ##
==========================================
+ Coverage   91.65%   91.82%   +0.16%     
==========================================
  Files         192      191       -1     
  Lines       11467    11521      +54     
==========================================
+ Hits        10510    10579      +69     
+ Misses        764      751      -13     
+ Partials      193      191       -2     
Impacted Files Coverage Δ
confmap/resolver.go 97.22% <98.71%> (+4.91%) ⬆️
confmap/provider.go 100.00% <100.00%> (ø)
confmap/provider/internal/provider.go 100.00% <100.00%> (ø)
...ernal/internalconsumertest/err_or_sink_consumer.go

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@bogdandrutu

This comment was marked as outdated.

@bogdandrutu bogdandrutu changed the title Extend Expand converter to support expanding values from any provider Add support in the confmap.Resolver to expand embedded config URIs inside configuration Jun 9, 2022
bogdandrutu added a commit that referenced this pull request Jun 10, 2022
This explains only how to provide the configuration via the `--config` file, after #4742 will update the embedded values option.

Signed-off-by: Bogdan Drutu <[email protected]>
confmap/provider.go Outdated Show resolved Hide resolved
confmap/resolver.go Outdated Show resolved Hide resolved
confmap/resolver.go Outdated Show resolved Hide resolved
return nil, err
}
mr.closers = append(mr.closers, ret.Close)
return ret.AsRaw()
Copy link
Member

Choose a reason for hiding this comment

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

To confirm: we don't want to apply expandValue recursively to the returned result here?

Copy link
Member Author

Choose a reason for hiding this comment

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

How many times would we do this? Until no changes (can get into infinite loop, maybe try for 10 times if still resolving then return error?)?

I thought it is not useful, but I can see now point in having it (after you asked for it). Let's discuss the behavior.

Copy link
Member

Choose a reason for hiding this comment

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

I can imagine 2 use cases:

  • If you have a local config file where env variables are used (quite common, e.g. in Splunk distro) you may want to specify that the value must be retrieved from a remote source instead of providing it directly.
  • The opposite: a config fetched from a remote location, but which refers to a local env variables (e.g. refer to $PATH or $TEMP).

How many times would we do this? Until no changes (can get into infinite loop, maybe try for 10 times if still resolving then return error?)?

Yeah, probably repeat until no more changes with some limit to avoid infinite looping. Any reasonable use case I can imagine should be 2 rounds, so limiting to something like 5 or 19 attempts should be fine.

Copy link
Member

Choose a reason for hiding this comment

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

I would suggest not introducing recursive expanding on this PR. We can forbid usage of $, { and } in the URI on this PR and deal with this problem later

Copy link
Member Author

@bogdandrutu bogdandrutu Jun 22, 2022

Choose a reason for hiding this comment

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

There are two problems, and probably we should address both, with different solutions:

  1. Embedding ${http://my.example.com?os=${env:OS_ENV}}
  2. Recursive ${file:/path/to/my/file} which returns a section of the config as a map[string]interface{} for example like {"key": ${env:VALUE}}. Then should we expand ${env:VALUE}?

For 1. I think we can simply error now. For 2. I think we cannot error, we need to resolve that, and that is what @tigrannajaryan was referring to.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I had the second case in my mind.
I am fine with deferring this to a future PR.

Copy link
Member

Choose a reason for hiding this comment

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

👍 Thanks both for clarifying. I think Tigran's suggestions above make sense and it's fine to support this now or later, whatever is easier

Choose a reason for hiding this comment

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

I am not clear at this point whether this can actually be introduced later. Will introducing embedding and recursive feature be an implementation detail or will it affect the user contract (like allowed symbols) ?

Copy link
Member

Choose a reason for hiding this comment

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

@jeromeinsf I think everyone agrees on leaving the implementation of (1) for later and restricting the allowed characters now. For (2), I believe @bogdandrutu wants to add support now with some recursion limit

Copy link
Member Author

Choose a reason for hiding this comment

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

(2) - Done

confmap/provider.go Show resolved Hide resolved
confmap/provider.go Show resolved Hide resolved
@bogdandrutu bogdandrutu force-pushed the expand branch 2 times, most recently from 5b92e6a to d84b374 Compare June 27, 2022 13:01
@github-actions
Copy link
Contributor

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

Copy link
Member

@mx-psi mx-psi left a comment

Choose a reason for hiding this comment

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

I only have one remaining question

func (mr *Resolver) expandValue(ctx context.Context, value interface{}) (interface{}, bool, error) {
switch v := value.(type) {
case string:
// If it doesn't have the format "${scheme:opaque}" no need to expand.
Copy link
Member

Choose a reason for hiding this comment

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

Something like ${HOST_IP}:4317 does not get expanded then? Why don't we use os.Expand like we are using on the expand provider?

Copy link
Member Author

@bogdandrutu bogdandrutu Jul 21, 2022

Choose a reason for hiding this comment

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

Because os.Expand only supports returning strings (not a partial sub-map).

See https://pkg.go.dev/os#Expand
func Expand(s string, mapping func(string) string) string

Copy link
Member

Choose a reason for hiding this comment

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

Right, but the problem of dealing with ${HOST_IP}:4317 still remains then? That would only be supported by environment variables?

Copy link
Member Author

@bogdandrutu bogdandrutu Jul 22, 2022

Choose a reason for hiding this comment

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

Do we want to support this? What is a good use-case? I don't see a reason to have ${HOST_IP}:4317, why hardcoded the port vs providing everything?

Copy link
Member

@mx-psi mx-psi Jul 22, 2022

Choose a reason for hiding this comment

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

Here are some examples on contrib using this with environment variables:

Why should environment variables work differently from other providers?

Copy link
Member

Choose a reason for hiding this comment

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

The ${THING_A}${THING_B} pattern is also interesting. Right now, IIUC, we interpret this as "get the thing with URI THING_A}${THING_B", which also seems counter to what I would expect to happen (I guess this relates to #5706 too).

Copy link
Member Author

Choose a reason for hiding this comment

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

To make progress, I disabled this feature from the Resolver. For the moment no way to enable this, but will send another PR that addresses the remaining issues and use a featuregate to enable this maybe.

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense. Sorry to bring this up so late, I hadn't realized until now

@mx-psi
Copy link
Member

mx-psi commented Jul 19, 2022

I created #5706 for the character set allowed in URIs. I think we can deal with this independently, since we potentially already have this problem with the environment variables (in principle any character except for = and NUL is allowed)

@bogdandrutu bogdandrutu force-pushed the expand branch 2 times, most recently from 978aa19 to 369aa72 Compare August 4, 2022 19:35
@bogdandrutu bogdandrutu merged commit 1c1a668 into open-telemetry:main Aug 4, 2022
@bogdandrutu bogdandrutu deleted the expand branch August 4, 2022 21:02
bogdandrutu added a commit to bogdandrutu/opentelemetry-collector that referenced this pull request Aug 5, 2022
Based on this experiment we developed stable code fore:
* Allowing support for multiple config "sources" via the "--config" flag and `confmap.Providers`
* Work in progress support to allow support for embedding partial configs, see open-telemetry#4742

Signed-off-by: Bogdan Drutu <[email protected]>
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.

Design and modify internal APIs to allow plugable full-config sources
7 participants