Skip to content
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

Support ListValue for metadata matcher #3964

Merged
merged 12 commits into from
Aug 7, 2018
Merged

Conversation

liminw
Copy link
Contributor

@liminw liminw commented Jul 26, 2018

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.

liminw added 3 commits July 26, 2018 16:06
Signed-off-by: Limin Wang <[email protected]>
Signed-off-by: Limin Wang <[email protected]>
@liminw
Copy link
Contributor Author

liminw commented Jul 26, 2018

/cc @yangminzhu @mattklein123 @lizan

@liminw
Copy link
Contributor Author

liminw commented Jul 26, 2018

/cc @rodaine

@@ -78,6 +78,18 @@ bool MetadataMatcher::match(const envoy::api::v2::core::Metadata& metadata) cons
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) {
const auto& lv = value.list_value().values(i);
if ((double_matcher_.has_value() && lv.kind_case() == ProtobufWkt::Value::kNumberValue &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@@ -68,8 +68,6 @@ import "validate/validate.proto";
// <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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liminw can we revert the comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I modified the origin comment to make it more accurate.

@@ -78,6 +78,18 @@ bool MetadataMatcher::match(const envoy::api::v2::core::Metadata& metadata) cons
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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Member

@lizan lizan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make the oneof ListMatch explicit in API.

@liminw
Copy link
Contributor Author

liminw commented Aug 2, 2018

@lizan @yangminzhu @mattklein123 I refactored the matcher code. The comments you mentioned should be addressed. PTAL.

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)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can check oneof_value_matcher_ outside the loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved if (oneof_value_matcher) to outside the loop.

@@ -68,8 +68,6 @@ import "validate/validate.proto";
// <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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liminw can we revert the comment?

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>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use unique_ptr here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel using shared_ptr is safer because a ValueMatcher instance could be referred in multiple places.

default:
NOT_REACHED_GCOVR_EXCL_LINE;
};
}

bool StringMatcher::match(const std::string& value) const {
bool StringMatcher::match(const ProtobufWkt::Value& value) const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

liminw added 2 commits August 2, 2018 14:59
Signed-off-by: Limin Wang <[email protected]>
Signed-off-by: Limin Wang <[email protected]>
@@ -162,6 +162,145 @@ TEST(MetadataTest, MatchPresentValue) {
EXPECT_FALSE(Envoy::Matchers::MetadataMatcher(matcher).match(metadata));
}

TEST(MetadataTest, MatchStringListValue) {
envoy::api::v2::core::Metadata metadata;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_*.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not remove the comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.


namespace Envoy {
namespace Matchers {

class DoubleMatcher {
class ValueMatcher;
typedef std::shared_ptr<const ValueMatcher> MatcherPtr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should name this ValueMatcherConstSharedPtr per style guide

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

liminw added 2 commits August 2, 2018 15:58
Signed-off-by: Limin Wang <[email protected]>
Signed-off-by: Limin Wang <[email protected]>
@liminw
Copy link
Contributor Author

liminw commented Aug 3, 2018

@lizan @mattklein123 @yangminzhu All your comments are addressed. Let me know if you have further comments. Thanks.

Copy link
Member

@lizan lizan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems the docs CI is failed, can you take a look?

}

if (oneof_value_matcher_) {
for (int i = 0; i < value.list_value().values_size(); ++i) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't for (const auto& lv : value.list_value().values()) work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to what you suggested.

@@ -68,8 +68,6 @@ import "validate/validate.proto";
// <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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

lizan
lizan previously approved these changes Aug 3, 2018
Copy link
Member

@lizan lizan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the diff looks a bit scary, IIUC this refactoring out Value -> ValueMatcher shouldn't break backward compatibility of those protos, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah from my eye LGTM, but would like if @htuch could double check.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, some small nits. Thank you!

return false;
}

double v = value.number_value();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

default:
NOT_REACHED_GCOVR_EXCL_LINE;
}
}

ListMatcher::ListMatcher(const envoy::type::matcher::ListMatcher& matcher) : matcher_(matcher) {
if (matcher_.match_pattern_case() != envoy::type::matcher::ListMatcher::kOneOf) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This should just be an ASSERT

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

NOT_REACHED_GCOVR_EXCL_LINE;
}

const auto& oneof = matcher_.one_of();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: local var not needed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


class NullMatcher : public ValueMatcher {
public:
NullMatcher() {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: not needed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

bool match(const ProtobufWkt::Value& value) const override;

private:
bool matcher_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

bool match(const ProtobufWkt::Value& value) const override;

private:
bool matcher_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Signed-off-by: Limin Wang <[email protected]>
@liminw
Copy link
Contributor Author

liminw commented Aug 6, 2018

Thanks @mattklein123! All comments are addressed.

@mattklein123 mattklein123 merged commit 3868326 into envoyproxy:master Aug 7, 2018
@liminw liminw deleted the groups branch August 7, 2018 18:18
@liminw liminw mentioned this pull request Sep 17, 2018
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants