-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
runtime: changing runtime features to be ABSL_FLAGs based #19880
Conversation
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
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.
Thanks for working on this.
Overall looks good.
Left a few comments. My concern is regarding some non-conventional usage of the previous Runtime Layer by extensions that I think could be broken by this.
#include "absl/strings/match.h" | ||
#include "absl/strings/str_replace.h" | ||
|
||
/* To add a runtime guard to Envoy, add 2 lines to this 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.
Could find a way to fetch the number of abseil flags, but if there is one, I suggest to make this constraint in code.
Specifically, adding a RELEASE_ASSERT in RuntimeFeatures
c'tor to validate that the number of abseil flags equals to the size of runtime_features + size of non-bool flags.
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 don't think that's necessary? If you add a runtime flag and only add it to the top, then when you try to access it you'll fail the ENVOY_BUG in runtimeFeatureEnabled so all existing tests going near that code path will hard fail. Meanwhile if we add that check it'll 100% break import so I'd prefer to stick with the ENVOY_BUG :-)
if (Runtime::LoaderSingleton::getExisting()) { | ||
return Runtime::LoaderSingleton::getExisting()->threadsafeSnapshot()->getInteger( | ||
std::string(feature), default_value); | ||
if (!absl::StartsWith(feature, "envoy.")) { |
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.
Thinking out loud here. Technically, an extension can use this method, and fetch a value that is set by RTDS.
I'm pretty confident no one does it, but if they do, should we have an ENVOY_BUG
or log a warning here?
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.
good call, refactored to catch both cases and done. Alternately I could also rename to getDeprecatedInteger and break folks' compile if they use it - think that's worth doing?
absl::flat_hash_map<std::string, bool> quiche_flags_override; | ||
for (const auto& it : flag_map) { | ||
if (absl::StartsWith(it.first, quiche::EnvoyQuicheReloadableFlagPrefix) && | ||
it.second.bool_value_.has_value()) { | ||
quiche_flags_override[it.first.substr(quiche::EnvoyFeaturePrefix.length())] = | ||
it.second.bool_value_.value(); | ||
} | ||
if (it.second.bool_value_.has_value() && isRuntimeFeature(it.first)) { |
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.
Again for the exceptional case where someone sets a non-conventional runtime flag by RTDS, we should probably have an ENVOY_BUG here.
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.
sorry you're saying if someone sets a boolean in their own code base envoy.reloadable_flag.not_in_runtime_features? Their code would crash on lookup any time they tried to reference the value so I'm not convinced anyone would compile that in but I can add a check regardless if you think it's worth 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.
Maybe my understanding of the previous runtime and loader is incorrect.
I thought that envoy.reloadable_flag.not_in_runtime_features can be set by RTDS (or more specifically when a new snapshot is created), and it can be read by any extension, no?
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.
Yes someone can set a random name, and it could be read from the snapshot, which is fine. It will only refresh a flag if the flag exists. I'm not sure what Alyssa's crashing comment is referring to?
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 Adi was asking if previously we supported a non-envoy-registered envoy.reloadable_feature being set via runtime config and fetched via runtimeFeatureEnabled(). It was not supported previously - you can set it in RTDS but runtimeFeatureEnabled checked that Envoy knew about it so you could only access it via explicit runtime checks. I think basically we have support parity here.
BTW: will it be possible to add the absl flags usage example into test/common/runtime/BUILD? |
Signed-off-by: Alyssa Wilk <[email protected]>
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.
FWIW //test/server/config_validation:xds_fuzz_test still fails - will debug tomorrow
#include "absl/strings/match.h" | ||
#include "absl/strings/str_replace.h" | ||
|
||
/* To add a runtime guard to Envoy, add 2 lines to this 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 don't think that's necessary? If you add a runtime flag and only add it to the top, then when you try to access it you'll fail the ENVOY_BUG in runtimeFeatureEnabled so all existing tests going near that code path will hard fail. Meanwhile if we add that check it'll 100% break import so I'd prefer to stick with the ENVOY_BUG :-)
if (Runtime::LoaderSingleton::getExisting()) { | ||
return Runtime::LoaderSingleton::getExisting()->threadsafeSnapshot()->getInteger( | ||
std::string(feature), default_value); | ||
if (!absl::StartsWith(feature, "envoy.")) { |
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.
good call, refactored to catch both cases and done. Alternately I could also rename to getDeprecatedInteger and break folks' compile if they use it - think that's worth doing?
absl::flat_hash_map<std::string, bool> quiche_flags_override; | ||
for (const auto& it : flag_map) { | ||
if (absl::StartsWith(it.first, quiche::EnvoyQuicheReloadableFlagPrefix) && | ||
it.second.bool_value_.has_value()) { | ||
quiche_flags_override[it.first.substr(quiche::EnvoyFeaturePrefix.length())] = | ||
it.second.bool_value_.value(); | ||
} | ||
if (it.second.bool_value_.has_value() && isRuntimeFeature(it.first)) { |
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.
sorry you're saying if someone sets a boolean in their own code base envoy.reloadable_flag.not_in_runtime_features? Their code would crash on lookup any time they tried to reference the value so I'm not convinced anyone would compile that in but I can add a check regardless if you think it's worth it.
"BTW: will it be possible to add the absl flags usage example into test/common/runtime/BUILD?" |
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
CC @envoyproxy/dependency-shepherds: Your approval is needed for changes made to |
One line patch change /lgtm deps |
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
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.
Thanks, LGTM modulo a nit.
/assign-from @envoyproxy/senior-maintainers
std::string envoy_name = swapPrefix(std::string(reflection.Name())); | ||
all_features_.emplace(envoy_name, feature); | ||
absl::optional<bool> value = reflection.TryGet<bool>(); | ||
if (value.has_value() && value.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.
nit: consider adding:
if (!value.has_value()) {
IS_ENVOY_BUG("Feature not found in ABSL flags...");
}
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 an assert - everything in that struct has to be a boolean by definition so really the value check is silly.
absl::StrCat("MainThreadLeak: [", test_info.test_suite_name(), ".", | ||
test_info.name(), "] test exited before main thread shut down")); | ||
} | ||
Runtime::RuntimeFeaturesDefaults::get().restoreDefaults(); |
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.
Interesting...
My initial thoughts were that this wouldn't work, because some tests will have a Scope defined as a class member, and override a runtime value in the c'tor, but if CI is green pass I guess that's ok.
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 all we need to do is set the flags back between unit tests
@envoyproxy/senior-maintainers assignee is @mattklein123 |
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
Signed-off-by: Alyssa Wilk <[email protected]>
CI sorted, ptal! |
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, left a question about the integer defaults.
} | ||
} | ||
|
||
void RuntimeFeatures::restoreDefaults() const { |
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.
All the calls to this method are done when ending tests/scope, however I don't see where the default values for the integer-based flags are set.
What am I missing?
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 just using the same values from where they're defined, which I snagged from the defaults to the getInteger code in call sites.
It's really inelegant but per the TODO I think I can get rid of most if not all of these so hopefully it won't be inelegant long.
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.
Nvm, my bad... I missed lines 66-72 in this file where these are initialized.
Thanks!
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
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.
At a high level LGTM! One question about upstreaming the absl path.
@@ -40,3 +40,16 @@ index 230bf1e..6e1b9e5 100644 | |||
|
|||
|
|||
// ABSL_OPTION_USE_INLINE_NAMESPACE | |||
diff --git a/absl/flags/commandlineflag.h b/absl/flags/commandlineflag.h |
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 this being upstreamed?
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 negotiating with the absl team about that or pragma changes yep
// TODO(12923): Document the Quiche reloadable flag setup. | ||
#ifdef ENVOY_ENABLE_QUIC | ||
void refreshQuicheReloadableFlags(const Snapshot::EntryMap& flag_map) { | ||
void refreshReloadableFlags(const Snapshot::EntryMap& flag_map) { |
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.
Just so I understand this is now being used for all refresh, right? So it's no longer H3 specific?
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.
correct, that's why I took quiche out of the name :-)
absl::flat_hash_map<std::string, bool> quiche_flags_override; | ||
for (const auto& it : flag_map) { | ||
if (absl::StartsWith(it.first, quiche::EnvoyQuicheReloadableFlagPrefix) && | ||
it.second.bool_value_.has_value()) { | ||
quiche_flags_override[it.first.substr(quiche::EnvoyFeaturePrefix.length())] = | ||
it.second.bool_value_.value(); | ||
} | ||
if (it.second.bool_value_.has_value() && isRuntimeFeature(it.first)) { |
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.
Yes someone can set a random name, and it could be read from the snapshot, which is fine. It will only refresh a flag if the flag exists. I'm not sure what Alyssa's crashing comment is referring to?
Note: this does NOT remove the runtime singleton, which will be done in a follow-up PR.
Risk Level: high
Testing: existing tests cover
Docs Changes: n/a
Release Notes:
Fixes #19847
Part of envoyproxy/envoy-mobile#2003