Adding configurator feature to dynamically inject configuration changes#374
Adding configurator feature to dynamically inject configuration changes#374
Conversation
| /* | ||
| MIT License | ||
|
|
||
| Copyright(c) 2020 Futurewei Cloud |
There was a problem hiding this comment.
Copyright date here and in other new files should be 2023
|
|
||
|
|
||
| private : | ||
| ConfigVar<String> _key{"key"}; |
There was a problem hiding this comment.
Are these variables used anywhere?
| }; | ||
|
|
||
| struct DELETE_ConfiguratorResponse { | ||
| String key; |
There was a problem hiding this comment.
Does the key need to be in the response for any of these?
| MAX_VERB = 250, // something we can use to prevent override of internal verbs. | ||
| CONFGURATOR_GET = 250, // used to configure get. | ||
| CONFGURATOR_SET = 251, // used to configure set. | ||
| CONFGURATOR_DELETE = 252, // used to configure clear messages. |
There was a problem hiding this comment.
I'm not sure this is where we want these defined, maybe Ivan has a suggestion.
| K2LOG_I(log::configuratortest, "Registering message handlers"); | ||
| auto ep = RPC().getServerEndpoint(TCPRPCProtocol::proto); | ||
|
|
||
| _singleTimer.setCallback([ep, this] { |
There was a problem hiding this comment.
I don't think you need a timer for this. You can assign the result from the make_ready_future call below to a member variable
| tso_child_pid=$! | ||
|
|
||
| # start CPO | ||
| ./build/src/k2/cmd/controlPlaneOracle/cpo_main ${COMMON_ARGS} -c1 --tcp_endpoints ${CPO} --data_dir ${CPODIR} --txn_heartbeat_deadline=10s --prometheus_port 63000 --assignment_timeout=1s --nodepool_endpoints ${EPS[@]} --tso_endpoints ${TSO} --tso_error_bound=100us --persistence_endpoints ${PERSISTENCE} & |
There was a problem hiding this comment.
Your configurator test is self-contained, you don't need to start any of the k2 components
| /* | ||
| MIT License | ||
|
|
||
| Copyright(c) 2020 Futurewei Cloud |
| // Verbs used by K2 internally | ||
| enum InternalVerbs : k2::Verb { | ||
| LIST_ENDPOINTS = 249, // used to discover the endpoints of a node | ||
| CONFGURATOR_GET = 250, // used to configure get. |
There was a problem hiding this comment.
You should rename these verbs to CONFIG_SET/GET/DELETE since they manage the config, not the configurator. Also, this enum has the MAX_VERB sentinel value of 250. You cannot repeat it. Since we already have a value for 249, You should list your verbs back from 249, so:
CONFIG_DELETE=246
CONFIG_GET=247
CONFIG_SET=248
|
|
||
| namespace k2 { | ||
|
|
||
| struct DELETE_ConfiguratorRequest { |
There was a problem hiding this comment.
Let's make the structs match the verb naming. So instead of DELETE_ConfiguratorRequest it should be ConfigDeleteRequest. Same for the rest
| struct DELETE_ConfiguratorRequest { | ||
| String key; | ||
| String value; | ||
| bool applyToAll; |
There was a problem hiding this comment.
We supply values for all primitive types in structs. This should be applyToAll{false}. Same for the rest
| }; | ||
|
|
||
| struct DELETE_ConfiguratorResponse { | ||
| String key; |
There was a problem hiding this comment.
no need to return the key.
| namespace k2 { | ||
|
|
||
| namespace log { | ||
| inline thread_local k2::logging::Logger configurator("k2::configurator_server"); |
There was a problem hiding this comment.
I would just call the name "k2::config". This name shows up in the logs so something shorter would be better.
| K2LOG_I(log::configurator, "Registering message handlers"); | ||
|
|
||
| RPC().registerRPCObserver<SET_ConfiguratorRequest, SET_ConfiguratorResponse>(InternalVerbs::CONFGURATOR_SET, [this](SET_ConfiguratorRequest&& request) { | ||
| K2LOG_I(log::configurator, "Received set for key: {}", request.key); |
| }); | ||
|
|
||
| RPC().registerRPCObserver<GET_ConfiguratorRequest, GET_ConfiguratorResponse>(InternalVerbs::CONFGURATOR_GET, [this](GET_ConfiguratorRequest&& request) { | ||
| K2LOG_I(log::configurator, "Received get for key: {}", request.key); |
| }); | ||
|
|
||
| RPC().registerRPCObserver<DELETE_ConfiguratorRequest, DELETE_ConfiguratorResponse>(InternalVerbs::CONFGURATOR_DELETE, [this](DELETE_ConfiguratorRequest&& request) { | ||
| K2LOG_I(log::configurator, "Received delete for key: {}", request.key); |
| K2LOG_I(log::configurator, "Received set for key: {}", request.key); | ||
| auto key = request.key; | ||
| auto value = request.value; | ||
|
|
There was a problem hiding this comment.
We probably need to validate the incoming value here before storing it in the config. you should check the boost map API to see if it does any config-related validation. If not, we should do it ourselves and return the appropriate status back to the RPC caller.
For log-related config, we need to apply the new value(for both set/delete) to the log system. The logic for that is here: https://github.com/futurewei-cloud/chogori-platform/blob/master/src/k2/appbase/Appbase.cpp#L81 and we may have to refactor it to reuse it.
You can also avoid code duplication like so:
return [request=std::move(request)] {
auto applier = [request] (auto& config) {
config.emplace(key, boost::program_options::variable_value(value, ""));
boost::program_options::notify(config);
return seastar::make_ready_future();
};
if (request.applyToAll) {
return ConfigDist().invoke_on_all(applier);
}
return applier();
}()
.then([] {
return RPCResponse(Statuses::S201_Created("ConfigSet accepted"), ConfigSetResponse{});
});| auto key = request.key; | ||
| auto value = request.value; | ||
|
|
||
| if (request.applyToAll) { |
There was a problem hiding this comment.
On a further thought, I think the validation and application to config should be delegated to the config here: https://github.com/futurewei-cloud/chogori-platform/blob/master/src/k2/config/Config.h
We should probably add the set/delete methods there which can also hide the all/local dispatch
Adding configurator feature to dynamically inject configuration changes, added a server and client.