-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Setup managed proxy environment with API client env vars #4374
Conversation
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 abstract approach seems right, but I have some weird feelings about tightly coupling the agent/proxy
package to a structure in the api
package.
I tried to keep the "interface" (in the abstract sense, not Go sense) of the agent/proxy.Manager
struct as loosely coupled as possible, to ease testing and refactoring in the future.
One idea perhaps is to just change the *api.Config
directly to an Env []string
field that would just be more generically "Append these enviornment variables to any launched proxies." This achieves the desired functionality without a tight coupling, and allows the consumer (agent
) to potentially inject more or fewer env vars in the future as necessary.
api/api.go
Outdated
@@ -405,6 +405,27 @@ func SetupTLSConfig(tlsConfig *TLSConfig) (*tls.Config, error) { | |||
return tlsClientConfig, nil | |||
} | |||
|
|||
func (c *Config) GenerateEnv() []string { | |||
env := make([]string, 10) |
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.
Nitpick but seems a little over-optimized. I dunno why we would but if we had to reorder stuff below or anything its a little bit much. Almost equally performant would be to just make with a cap of 10 make([]string, 0, 10)
and use append
below which will never realloc and is pretty optimized by the Go compiler.
agent/config/runtime.go
Outdated
cfg.Scheme = "http" | ||
} else if len(unixAddrs) > 0 { | ||
cfg.Address = "unix://" + unixAddrs[0] | ||
cfg.Scheme = "http" |
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.
Is the scheme here right?
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 client is still talking HTTP just over a unix socket instead of a TCP connection. So it depends on how this param is used in the api code - @mkeeler maybe add a comment about why this is http
and not unix
since it's not obvious if this is right.
I think this will actually get ignored because the address has a scheme in it but in that case I'd suggest we leave it blank.
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.
You are right this will be ignored currently.
While there isn't much point as all the data is flowing through your kernel, you could do https over the unix socket. Having the Scheme set to http for both seemed logical for what protocol we intend to talk over the l4 transport.
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.
@mitchellh I have to take the blame for the api.Config
thing.
My gut feeling was that I wanted to encapsulate config in a proper struct - I initially suggested a new struct in config
package for it until Matt pointed out it would just be a duplicate of api.Config
.
I have only fuzzy reasons for preferring that - having a map or slice of env vars plumbed through several layers feels like it will end up being hacked to support transporting stuff we don't actually need to put in ENV but do need some other place like in a JSON payload sent to configure something.
Keeping a struct felt like a cleaner semantic thing to plumb around between components than a bag of stuff for that reason. "Here is all you need to configure API clients" vs. "Here is some stuff for the ENV".
It's potentially over-engineering though - we don't have any need for these except for setting ENV vars for now so we could defer the abstraction for now.
I'm happy to leave it as a ProxyEnv []string
or something for now but I'd still marginally prefer a struct - one in config
if we thing the api
import is unclean although that introduces more duplication.
agent/config/runtime.go
Outdated
cfg.Scheme = "http" | ||
} else if len(unixAddrs) > 0 { | ||
cfg.Address = "unix://" + unixAddrs[0] | ||
cfg.Scheme = "http" |
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 client is still talking HTTP just over a unix socket instead of a TCP connection. So it depends on how this param is used in the api code - @mkeeler maybe add a comment about why this is http
and not unix
since it's not obvious if this is right.
I think this will actually get ignored because the address has a scheme in it but in that case I'd suggest we leave it blank.
It would be just as easy to generate the []string of env vars one level up in the agent code. I have no issues with not propagating the api Config struct into the proxy. |
agent/proxy/manager.go
Outdated
@@ -434,7 +437,7 @@ func (m *Manager) newProxy(mp *local.ManagedProxy) (Proxy, error) { | |||
} | |||
|
|||
// Pass in the environmental variables for the proxy process | |||
cmd.Env = os.Environ() | |||
cmd.Env = append(os.Environ(), m.ProxyEnv...) |
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 de-dupe this? I'm not sure what the behaviour is if any of the CONSUL_* vars are already set in agent's ENV across different platforms.
I feel like we should allow the agent's own ENV vars to take precedence. In general if they are set they are likely set to same thing anyway but it provides a nice way to be able to override the choice of which protocol/listener to pass which we could document. The edge case of some legacy garbage value in ENV being used seems like a reasonable trade.
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.
As for de-dupe it should be unnecessary. With the current code the ProxyEnv vars will be used. However we could just do it like this append(m.ProxyEnv, os.Environ()...)
and then the agents env will be used.
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.
Another note is that regardless of the env we set they can still use a custom proxy command like env CONSUL_HTTP_ADDR=.... <path to consul> connect proxy
to override anything we set.
c15c558
to
85aa770
Compare
Proxy now doesn’t need to know anything about the api as we pass env vars to it instead of the api config.
85aa770
to
c54b43b
Compare
@banks What @mkeeler suggested (and ended up doing I see now) is exactly what I was thinking: you just generate the flat slice one level up. I think the argument for "over-engineering" can fall on either side, but I think lowering cross-package requirements unless they make a lot of sense or are obviously needed is generally the right design decision. Beyond that, |
Added* to the above: I should note that I think using |
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.
Agreed this looks good.
If Env contains duplicate environment keys, only the last
value in the slice for each duplicate key is used.
So yeah dupes are not a big deal. The ability to do global override seems nicish with env merged the other way but you're right that it can be done in the proxy command anyway so I think this is good.
This adds:
What I have tested thus far: