-
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
Agent Auto Configuration: Refactor RPC endpoint to use interface delegate #8253
Conversation
A few things I still want to think over are:
|
15db3f7
to
82b603d
Compare
agent/consul/auto_config_endpoint.go
Outdated
type AutoConfigDelegate interface { | ||
GetConfig() *Config | ||
CreateACLToken(template *structs.ACLToken) (*structs.ACLToken, error) | ||
DatacenterJoinAddresses(segment string) ([]string, error) | ||
TLSConfigurator() *tlsutil.Configurator | ||
ForwardRPC(method string, info structs.RPCInfo, args, reply interface{}) (bool, error) |
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.
What do you think of something like AutoConfigBackend
for the name of this interface? Delegate is kind of implied by it being an interface.
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 sounds fine to me and I will make the change.
What do you think about the interface? In particular I was debating about whether this should all go into a single interface or multiple as well as whether the Config and TLS Configurator should just be provided to the AutoConfig RPC struct instead of retrieved via the interface.
Setting the TLS Configurator seems simple enough. The Config is less straightforward though as its reloadable. The server would have to track all the things it needed to notify about new configuration.
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 interface looks reasonable to me. I started digging into how it was used a bit, but I ran out of time.
For config reload, an idea I have been playing with would be to have all the components that need to reload implement an interface. I'm not sure exactly what that needs to look like yet, but I think it might be something like this:
type Reloadable interface {
ReloadStart() (done func())
UpdateConfig(config.Config)
}
Any component that needs to pause and lock all operations can do so with ReloadStart
(and unlock with done
), and everything would accept the new config from UpdateConfig()
.
The agent would store a []Reloadable
and call all the ReloadStart()
first, then all the UpdateConfig()
, and finally all the done()
in reverse order.
To get around the import cycle with config
UpdateConfig
might take a closure instead of a config struct, I'm not sure.
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.
So I made a few changes since your review.
I got rid of the GetConfig
and TLSConfigurator
methods in the interface. Instead those concrete types are passed into a constructor. I also noticed that the only fields on the Config that were used were not runtime reloadable so I didn't bother implementing the reloadability of the configuration (the TLS CA certs are runtime reloadable but the Agent
handles updating the shared tls configurator)
As for whats left in the interface, the 3 functions only relation is that they are needed by this RPC endpoint. With another soon to be opened PR I will be adding a couple more related to signing certificates and getting the latest connect CA roots. Still there isn't a strong relationship between these methods. I could have split this into multiple interfaces but that seems a little excessive for now.
3ea5768
to
fa1b452
Compare
It would appear that something in my tests hang forever now. |
… type Instead it has an interface which can be mocked for better unit testing that is deterministic and not prone to flakiness.
Also get rid of the preexisting shim in server.go that existed before to have this name just call the unexported one.
fa1b452
to
f2f3273
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.
For 1, I kind of like the idea of passing in the configuration and then having the Server
or something call ReloadConfig
on the auto-config endpoint. That mimics the way we reload config from agent.Agent
-> consul.Server
and could be a good pattern to follow as we split up more endpoints. Not sure if there are any complications hidden here though.
Given that, I think passing in the tlsConfigurator
would also make sense, so that all configuration is passed in on initialization.
As for 2, splitting out the interface, I don't think I have a strong opinion. I could see splitting out interfaces for each like: RPCForwarder
, TokenCreator
, and DatacenterReader
(very quickly named), but I am not sure practically how much value that gives us at the moment. 🤷♂️ Do you see an advantage in splitting out more interfaces?
This is instead of having the AutoConfigBackend interface provide functions for retrieving them. NOTE: the config is not reloadable. For now this is fine as we don’t look at any reloadable fields. If that changes then we should provide a way to make it reloadable.
I mentioned it in some PR comment replies but for future onlookers, I decided to pass in an For now we are not using any reloadable configurations on the |
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.
LGTM. I think it is reasonable to not deal with reloading config for now and wait until if/when we need to. 👍
This PR does a couple things.
The first commit does:
Cluster.AutoConfig
RPC toAutoConfig.InitialConfiguration
. This change includes updating the client side code to use the correct name.AutoConfig
RPC endpoint struct to take in an interface object that has methods to provide all the data it needs. Some logic (creating ACL tokens & generating a list of join addresses) was moved out of the RPC endpoint and into methods on theServer
type itself. This simplifies the RPC endpoint quite a bit but also allows testing with fewer full test servers and utilizing more mocks. Utilizing the mocks to inject certain data also allows the tests to be simpler as much of the previous non-determinism that was in auto generated IDs and times has moved to being a function of the interface.The second commit just renames
Server.forward
toServer.ForwardRPC
. This satisfies the interface created in the first commit and removes the temporary shim method in place.You should be able to glance at the second commit but then focus in on just the first one for all the more substantial changes.
This PR does not produce any functional difference and is simply refactoring.