-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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 for DOCKER_CUSTOM_HEADERS env-var (experimental) #5098
Conversation
dc2c0f1
to
0d6b805
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5098 +/- ##
==========================================
+ Coverage 61.05% 61.48% +0.43%
==========================================
Files 296 299 +3
Lines 20814 20845 +31
==========================================
+ Hits 12707 12817 +110
+ Misses 7196 7114 -82
- Partials 911 914 +3 |
I'm wondering about the utility of adding an env var that completely replaces headers set via over settings (such as through the config file) vs just appending/overriding headers with the same name. I feel like in most cases, adding headers might be more useful, and if in some cases there's a need to overwrite some values, that can be done on a per-header basis, rather than completely ignoring otherwise configured headers. |
cli/command/cli_options.go
Outdated
csvReader := csv.NewReader(strings.NewReader(value)) | ||
fields, err := csvReader.Read() | ||
if err != nil { | ||
return errdefs.InvalidParameter(errors.Wrapf(err, "failed to set custom headers from %s environment variable", envOverrideHTTPHeaders)) |
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.
From the docs i see these three main error conditions on csvReader.Read()
:
-
If the record has an unexpected number of fields, Read returns the record along with the error ErrFieldCount.
Given we'll only have a single "row" of data,
ErrFieldCount
shouldn't really occur; -
If the record contains a field that cannot be parsed, Read returns a partial record along with the parse error. The partial record contains all fields read before the error.
I don't think we want to manage partial records, so we should return when ending up on that error;
-
If there is no data left to be read, Read returns nil, io.EOF.
We shouldn't ever encounter an empty reader
Given the above, in this error msg shall we mention that the CSV passed in the DOCKER_CUSTOM_HEADERS
is likely malformed? IIUC that'd be the most likely reason for encountering the error, and might be a bit more helpful to the user than this fairly generic message. WDYT?
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.
Hm, yes, good point; I was thinking that the CSV error might be useful, but perhaps it's not, and we should just produce a generic "this is likely the wrong format, we expect a comma-separated list of key=value
.
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.
fair point, always try to make user facing errors "explicit" just in case (so they're in our control rather then depending on the library maintainers). No hard feelings if the error it returns is good enough👍
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.
We should look indeed what the errors look like, and either "replace" all errors it produces, or if it's only a specific type; for that type.
I haven't found the time yet to try what they look like (perhaps we need to add a test-case for it)
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 updated the error to not include the CSV error, and made it more generic
cli/command/cli_options.go
Outdated
|
||
if v == "" { | ||
// Ignore empty values, and consider them to not be set | ||
continue |
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'm not totally sure we should ignore empty values, as it could add some confusion to the user (maybe they were expecting the header to be set but empty). Are there scenarios in which we might expect this to occur?
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.
My somewhat anticipation here was for My-Header=${SOME_ENV_VAR}
. I'd be ok with starting with this being an error condition though (which would still keep all options open)
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.
OK, gave this some thinking, and it's probably fine to just set an empty value, and leave it an exercise to the user to handle My-Header=${SOME_ENV_VAR}
in situations where $SOME_ENV_VAR
is not set (they can use the magic of (Ba)sh to handle unset env-vars.
Yes, this is always the tricky one; override vs merge. I guess in most situations, an env-var would override config ( The tricky part with merging is that we would also need a way to unset env-vars; in some parts of our code, I think we have "empty value" meaning "remove", although that one was specifically for User-Agent (allowing removing the user-agent); https://github.com/moby/moby/blob/989426d303a334db4d97f72efe6637d64220d01a/client/request.go#L244-L266 |
0d6b805
to
af2dde4
Compare
I updated the PR and added a WARNING to the GoDoc to mention that the behavior may change (headers to be appended in future, and only overwrite same-name ones) |
af2dde4
to
5713d6d
Compare
5713d6d
to
2f336a6
Compare
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.
overall LGTM, some minor comments
cli/command/cli_options.go
Outdated
@@ -108,3 +113,107 @@ func WithAPIClient(c client.APIClient) CLIOption { | |||
return nil | |||
} | |||
} | |||
|
|||
// envOverrideHTTPHeaders is the name of the environment variable that can be |
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.
nit: a bit pedantic, but should we go with only one way of writing these in the docstrings?
environment variable
environment-variable
env-var
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.
Heh, yeah, I keep making that mistake. Changed to environment-variable
which seems the most common use, but we should make a pass at looking through our use for consistency
cli/command/cli_options.go
Outdated
k = strings.TrimSpace(k) | ||
|
||
if k == "" { | ||
return errdefs.InvalidParameter(errors.Errorf("failed to set custom headers from %s environment variable: value contains a key=value pair with an empty key", envOverrideHTTPHeaders)) |
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.
could it make sense to print out the wrong key-value in this error message like we do below, to help the user in spotting the bad part of the string? I'm imagining something similar to:
failed to set custom headers from DOCKER_CUSTOM_HEADERS environment variable: value contains a key=value pair with an empty key (' =somevalue')
where the error shown also contains the potential whitespace (so k before trimming the space)
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.
ah, yes, probably works; let me look
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.
Added; I decided to change the error-messages to use '%s'
(not %q
) to prevent double-escaped quotes in the output
| `DOCKER_API_VERSION` | Override the negotiated API version to use for debugging (e.g. `1.19`) | | ||
| `DOCKER_CERT_PATH` | Location of your authentication keys. This variable is used both by the `docker` CLI and the [`dockerd` daemon](https://docs.docker.com/reference/cli/dockerd/) | | ||
| `DOCKER_CONFIG` | The location of your client configuration files. | | ||
| `DOCKER_CONTENT_TRUST_SERVER` | The URL of the Notary server to use. Defaults to the same URL as the registry. | | ||
| `DOCKER_CONTENT_TRUST` | When set Docker uses notary to sign and verify images. Equates to `--disable-content-trust=false` for build, create, pull, push, run. | | ||
| `DOCKER_CONTEXT` | Name of the `docker context` to use (overrides `DOCKER_HOST` env var and default context set with `docker context use`) | | ||
| `DOCKER_CUSTOM_HEADERS` | (Experimental) Configure [custom HTTP headers](#custom-http-headers) to be sent by the client. Headers must be provided as a comma-separated list of `name=value` pairs. This is the equivalent to the `HttpHeaders` field in the configuration file. | |
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 think we should specify also here that, when the env var is populated, it's values will replace all values set via the configuration file
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.
Yeah, I tried to shorten the description here, otherwise the whole table would be re-formatted 😂
I think we may need to do another pass at docs in a follow-up; I'm keeping this as-is for now, and we can do a follow-up to improve things if that's ok for you.
This environment variable allows for setting additional headers to be sent by the client. Headers set through this environment variable are added to headers set through the config-file (through the HttpHeaders field). This environment variable can be used in situations where headers must be set for a specific invocation of the CLI, but should not be set by default, and therefore cannot be set in the config-file. WARNING: If both config and environment-variable are set, the environment variable currently overrides all headers set in the configuration file. This behavior may change in a future update, as we are considering the environment variable to be appending to existing headers (and to only override headers with the same name). Signed-off-by: Sebastiaan van Stijn <[email protected]>
2f336a6
to
6638deb
Compare
This environment variable allows for setting additional headers to be sent by the client. Headers set through this environment variable are added to headers set through the config-file (through the HttpHeaders field).
This environment variable can be used in situations where headers must be set for a specific invocation of the CLI, but should not be set by default, and therefore cannot be set in the config-file.
variable currently overrides all headers set in the configuration file.
This behavior may change in a future update, as we are considering the
environment variable to be appending to existing headers (and to only
override headers with the same name).
- What I did
- How I did it
- How to verify it
- Description for the changelog
- A picture of a cute animal (not mandatory but encouraged)