Support ListValue for metadata matcher#3964
Conversation
Signed-off-by: Limin Wang <liminwang@google.com>
Signed-off-by: Limin Wang <liminwang@google.com>
Signed-off-by: Limin Wang <liminwang@google.com>
|
/cc @rodaine |
source/common/common/matchers.cc
Outdated
| case ProtobufWkt::Value::kListValue: | ||
| for (int i = 0; i < value.list_value().values_size(); ++i) { | ||
| const auto& lv = value.list_value().values(i); | ||
| if ((double_matcher_.has_value() && lv.kind_case() == ProtobufWkt::Value::kNumberValue && |
There was a problem hiding this comment.
I think you should also check null_matcher_ unless you mention it in the doc that null_matcher_ is not supported in list.
Another Nit: as the matcher is stable so you should be able to decide the expected value and type from the matcher outside the for-loop, and during the for-loop just check if lv has the value and type. This should make it faster.
| // <envoy_api_msg_config.rbac.v2alpha.Principal>`. | ||
| message MetadataMatcher { | ||
| // Specifies the segment in a path to retrieve value from Metadata. | ||
| // Note: Currently it's not supported to retrieve a value from a list in Metadata. This means it |
There was a problem hiding this comment.
I think this comment should remain, we still don't support to retrieve a value from a list.
And the comment in line 80 should be updated that it now supports to compare a value to a list, but such comparison only supports primitive values in a list, embedded values in a list are still not supported.
There was a problem hiding this comment.
We already support list value. The current match method is one_of, as documented in API. I don't think we need the comments here. BTW, list embedded in another list is supported with the new change.
There was a problem hiding this comment.
@liminw these comment are still valid for PathSegment, with this PR it will support matching to a list, doesn't mean we can specify a PathSegment that retrieve a value from a list.
There was a problem hiding this comment.
I modified the origin comment to make it more accurate.
source/common/common/matchers.cc
Outdated
| case ProtobufWkt::Value::kBoolValue: | ||
| return (bool_matcher_.has_value() && *bool_matcher_ == value.bool_value()); | ||
| case ProtobufWkt::Value::kListValue: | ||
| for (int i = 0; i < value.list_value().values_size(); ++i) { |
There was a problem hiding this comment.
I don't think we should automatically extend the value matchers to list (and treat it is matched when one of the list element matches to it), can we make a ListMatch in matcher/metadata.proto, and make this behavior explicitly from the API? In future we may want to do more than oneof match for lists.
lizan
left a comment
There was a problem hiding this comment.
Please make the oneof ListMatch explicit in API.
Signed-off-by: Limin Wang <liminwang@google.com>
Signed-off-by: Limin Wang <liminwang@google.com>
|
@lizan @yangminzhu @mattklein123 I refactored the matcher code. The comments you mentioned should be addressed. PTAL. |
source/common/common/matchers.cc
Outdated
| for (int i = 0; i < value.list_value().values_size(); ++i) { | ||
| const auto& lv = value.list_value().values(i); | ||
|
|
||
| if (oneof_value_matcher_ && oneof_value_matcher_->match(lv)) { |
There was a problem hiding this comment.
You can check oneof_value_matcher_ outside the loop.
There was a problem hiding this comment.
Moved if (oneof_value_matcher) to outside the loop.
| // <envoy_api_msg_config.rbac.v2alpha.Principal>`. | ||
| message MetadataMatcher { | ||
| // Specifies the segment in a path to retrieve value from Metadata. | ||
| // Note: Currently it's not supported to retrieve a value from a list in Metadata. This means it |
| MatcherPtr ValueMatcher::create(const envoy::type::matcher::ValueMatcher& v) { | ||
| switch (v.match_pattern_case()) { | ||
| case envoy::type::matcher::ValueMatcher::kNullMatch: | ||
| return std::make_shared<const NullMatcher>(); |
There was a problem hiding this comment.
Can we use unique_ptr here?
There was a problem hiding this comment.
I feel using shared_ptr is safer because a ValueMatcher instance could be referred in multiple places.
| } | ||
|
|
||
| bool StringMatcher::match(const std::string& value) const { | ||
| bool StringMatcher::match(const ProtobufWkt::Value& value) const { |
There was a problem hiding this comment.
Previously, the StringMatcher accepts a simple string so it could be used in anywhere with a string value, now it only can be only used with Value? is this expected?
There was a problem hiding this comment.
Yes, match() is a virtual function defined in the parent class ValueMatcher. StringMatcher just implements the overrides here. If in the future, there is a need to use the primitive string as the parameter, we can always add that function.
Signed-off-by: Limin Wang <liminwang@google.com>
Signed-off-by: Limin Wang <liminwang@google.com>
| } | ||
|
|
||
| TEST(MetadataTest, MatchStringListValue) { | ||
| envoy::api::v2::core::Metadata metadata; |
There was a problem hiding this comment.
Can you make a utility function like this https://github.com/envoyproxy/envoy/blob/master/test/common/http/header_utility_test.cc#L17 and use it to construct those test fixtures from YAML? It is hard to read from the code with multiple mutable_*.
There was a problem hiding this comment.
Added a utility function.
| * @return true if it's matched otherwise false. | ||
| */ | ||
| bool match(const std::string& value) const; | ||
| bool match(const ProtobufWkt::Value& value) const override; |
There was a problem hiding this comment.
I don't think the comments here is needed. It's overriding match() defined in parent class ValueMatcher. If we add the comment back, it would just repeats the one in ValueMatcher class.
source/common/common/matchers.h
Outdated
|
|
||
| class DoubleMatcher { | ||
| class ValueMatcher; | ||
| typedef std::shared_ptr<const ValueMatcher> MatcherPtr; |
There was a problem hiding this comment.
You should name this ValueMatcherConstSharedPtr per style guide
Signed-off-by: Limin Wang <liminwang@google.com>
Signed-off-by: Limin Wang <liminwang@google.com>
|
@lizan @mattklein123 @yangminzhu All your comments are addressed. Let me know if you have further comments. Thanks. |
lizan
left a comment
There was a problem hiding this comment.
seems the docs CI is failed, can you take a look?
source/common/common/matchers.cc
Outdated
| } | ||
|
|
||
| if (oneof_value_matcher_) { | ||
| for (int i = 0; i < value.list_value().values_size(); ++i) { |
There was a problem hiding this comment.
doesn't for (const auto& lv : value.list_value().values()) work?
There was a problem hiding this comment.
Changed to what you suggested.
| // <envoy_api_msg_config.rbac.v2alpha.Principal>`. | ||
| message MetadataMatcher { | ||
| // Specifies the segment in a path to retrieve value from Metadata. | ||
| // Note: Currently it's not supported to retrieve a value from a list in Metadata. This means it |
There was a problem hiding this comment.
@liminw these comment are still valid for PathSegment, with this PR it will support matching to a list, doesn't mean we can specify a PathSegment that retrieve a value from a list.
Signed-off-by: Limin Wang <liminwang@google.com>
Signed-off-by: Limin Wang <liminwang@google.com>
lizan
left a comment
There was a problem hiding this comment.
LGTM, thanks! one comment left for other reviewers.
|
|
||
| // Specifies the way to match a ProtobufWkt::Value. Primitive values and ListValue are supported. | ||
| // StructValue is not supported and is always not matched. | ||
| message ValueMatcher { |
There was a problem hiding this comment.
Although the diff looks a bit scary, IIUC this refactoring out Value -> ValueMatcher shouldn't break backward compatibility of those protos, right?
There was a problem hiding this comment.
Yeah from my eye LGTM, but would like if @htuch could double check.
mattklein123
left a comment
There was a problem hiding this comment.
LGTM, some small nits. Thank you!
source/common/common/matchers.cc
Outdated
| return false; | ||
| } | ||
|
|
||
| double v = value.number_value(); |
source/common/common/matchers.cc
Outdated
| } | ||
|
|
||
| ListMatcher::ListMatcher(const envoy::type::matcher::ListMatcher& matcher) : matcher_(matcher) { | ||
| if (matcher_.match_pattern_case() != envoy::type::matcher::ListMatcher::kOneOf) { |
There was a problem hiding this comment.
nit: This should just be an ASSERT
source/common/common/matchers.cc
Outdated
| NOT_REACHED_GCOVR_EXCL_LINE; | ||
| } | ||
|
|
||
| const auto& oneof = matcher_.one_of(); |
source/common/common/matchers.h
Outdated
|
|
||
| class NullMatcher : public ValueMatcher { | ||
| public: | ||
| NullMatcher() {} |
source/common/common/matchers.h
Outdated
| bool match(const ProtobufWkt::Value& value) const override; | ||
|
|
||
| private: | ||
| bool matcher_; |
source/common/common/matchers.h
Outdated
| bool match(const ProtobufWkt::Value& value) const override; | ||
|
|
||
| private: | ||
| bool matcher_; |
Signed-off-by: Limin Wang <liminwang@google.com>
|
Thanks @mattklein123! All comments are addressed. |
Description: This change added support for ListValue type in MetadataMatcher.
Risk Level: Low
Testing: Added unit tests.
Docs Changes: N/A.
Release Notes: N/A.