-
Notifications
You must be signed in to change notification settings - Fork 62
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
Allow multiple matchers for NetObserv multi-tenancy (NETOBSERV-171) #440
Conversation
/cc @periklis |
api/logs/v1/labels_enforcer.go
Outdated
expr.Walk(func(expr interface{}) { | ||
switch le := expr.(type) { | ||
case *logqlv2.StreamMatcherExpr: |
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 considering the observatorium/opa-openshift#15 draft PR it looks like the opa.matcher
(considering we can only do vector or vector
with stream label matcher in LogQL) is overloaded. The label.Matchers
should maybe include a field that tells if they are going to be appended as label selectors in StreamMatcherExpr
or as line filters., e.g.:
expr.Walk(func(expr interface{}) {
switch le := expr.(type) {
case *logqlv2.StreamMatcherExpr:
le.AppendMatchers(lm)
case *logqlv2.LineFilterExpr: // I believe our syntax does not support this case yet
if mInfo.LogicalOp == logicalOr {
le.AppendORMatchers(mInfo.Matchers)
} else {
le.AppendMatchers(mInfo.Matchers)
}
default:
// Do nothing
}
})
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, or we do line filters anyway, regardless if it's vectors or not.
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.
Looking on the StreamMatchersExpr.String()
implementation below I see that you circuit break with a closing curly brace in case of an or-Matcher and move forward with a line filter. This looks very to me. In the above sample I propose to clearly render or-Matchers as line filters, e.g. by appending a new line filter with or-s at the end of the query.
PS: I mention Line Filter above, but I am not sure if it the right expression. IIRC logical expressions on matchers are supported only on label filters and not line filters. Please consider the parser tests for the right expression.
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 tried your suggested approach at first but I hit an issue: if I remember correctly, Line filters "walker" is only invoked if there are actually line filters in the initial expression, it isn't invoked at all if there are none. Or maybe I didn't proceed like what you were thinking about... I can retry and let you see the issue if you want
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 the approach you suggest would work but requires a little more refactoring of the traversal pattern
JIRA: https://issues.redhat.com/browse/NETOBSERV-171 - Updated result data from OPA Authz - Query injection needs to handle several matchers, and logical OR (this is WIP) - Update tests
It produces valid logql, however the parser is currently failing to parse it :(
- Use strconv.Quote to preserve string escaping - Add test - Makefile: allow building with podman
@periklis this one is ready for review |
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.
In general the approach looks good to me. However I suggest we keep rendering rendering stream matchers independently from label filters with logical expressions.
api/logs/v1/labels_enforcer.go
Outdated
expr.Walk(func(expr interface{}) { | ||
switch le := expr.(type) { | ||
case *logqlv2.StreamMatcherExpr: |
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.
Looking on the StreamMatchersExpr.String()
implementation below I see that you circuit break with a closing curly brace in case of an or-Matcher and move forward with a line filter. This looks very to me. In the above sample I propose to clearly render or-Matchers as line filters, e.g. by appending a new line filter with or-s at the end of the query.
PS: I mention Line Filter above, but I am not sure if it the right expression. IIRC logical expressions on matchers are supported only on label filters and not line filters. Please consider the parser tests for the right expression.
- Grammar has to be updated so that LogQueryExpr doesn't translate into a simple StreamMatcherExpr when there is no lof pipeline - New func LogQueryExpr.AppendPipelineMatchers that injects "or" matchers - update tests
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.
In general looks good to me. I will add my approve once I have tested this in companion with observatorium-api on our Loki Operator release branches.
logql/v2/ast.go
Outdated
@@ -61,17 +61,15 @@ func (s *StreamMatcherExpr) Walk(fn WalkFn) { | |||
func (s *StreamMatcherExpr) String() string { | |||
var sb strings.Builder | |||
|
|||
sb.WriteString("{") | |||
|
|||
sb.WriteRune('{') |
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 is the value of this? I am just curious.
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 assume it's supposed to be more optimized but I admit I have no certitude I could not find a clear statement on that while googling, and doing a quick benchmark isn't conclusive. I can revert then ...
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.
Let's keep it the old way
logql/v2/parser_test.go
Outdated
func TestQuotesEncode(t *testing.T) { | ||
expr, err := ParseExpr(`{app="test"}`) | ||
require.NoError(t, err) | ||
require.Equal(t, `{app="test"}`, expr.String()) | ||
|
||
expr, err = ParseExpr("{app=\"test\"}|~`key\":\"val\"`") | ||
require.NoError(t, err) | ||
require.Equal(t, `{app="test"} |~ "key\":\"val\""`, expr.String()) | ||
} |
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.
Can we eliminate testify usage here? This repo is under shared maintenance with many teams and we don't have any vote on changing the way we write tests.
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.
btw: I tend to write flat tests rather than test cases arrays (aka table-driven tests), that's a personal preference, but since the norm here seems to be test cases arrays, I can definitely comply with it.
logql/v2/parser_test.go
Outdated
{ | ||
input: `{first="value"} |~ "key\":\"val\""`, | ||
expr: &LogQueryExpr{ | ||
filter: LogPipelineExpr{ | ||
&LogFilterExpr{ | ||
filter: "|~", | ||
value: "key\":\"val\"", | ||
}, | ||
}, | ||
left: &StreamMatcherExpr{ | ||
matchers: []*labels.Matcher{ | ||
{ | ||
Type: labels.MatchEqual, | ||
Name: "first", | ||
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.
What is the value added by this test case not covered by any of the existing?
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.
It's indeed similar to TestQuotesEncode
below except this one tests double-quotes whereas the other one tests backquotes. I can move it to the TestQuotesEncode
test, maybe it will be more clear & consistent
logql/v2/parser_test.go
Outdated
{ | ||
input: `{first="value"} | second=~"foo|bar" or third=~"foo|bar"`, | ||
expr: &LogQueryExpr{ | ||
filter: LogPipelineExpr{ | ||
&LogLabelFilterExpr{ | ||
labelName: "second", | ||
comparisonOp: "=~", | ||
labelValue: "foo|bar", | ||
right: []*LogLabelFilterExpr{ | ||
{ | ||
labelName: "third", | ||
comparisonOp: "=~", | ||
labelValue: "foo|bar", | ||
isNested: true, | ||
chainOp: "or", | ||
}, | ||
}, | ||
}, | ||
}, | ||
left: &StreamMatcherExpr{ | ||
matchers: []*labels.Matcher{ | ||
{ | ||
Type: labels.MatchEqual, | ||
Name: "first", | ||
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.
Isn't this test case already covered by the next one? Or is this all about testing the strconv.Quote
? If yes, on the last question then we can drop this test as per strconv.Quote
having enough tests in the Golang std library.
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 I wrote this test because it was the closest I had from the actual netobserv queries with tenancy matchers. So it helped me while doing the implementation. But you're right that it overlaps with other tests. I can remove 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.
Still looks good to me
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.
Approving this PR as is right now. Waiting for merge until I get a green light from OpenShift Logging release manager as per main branch being used for multiple releases right now (i.e. OpenShift Logging 5.5, 5.6 and upcoming 5.7).
JIRA: https://issues.redhat.com/browse/NETOBSERV-171
In short, without this PR, only one matcher injection for multi-tenancy is allowed: e.g.
namespace=foo
NetObserv is an observability solution dedicated to the network, that stores flow logs in Loki. Implementing multi-tenancy for NetObserv requires injecting more complex matchers for handling flow logs sources and destinations: e.g.
src-namespace=foo OR dst-namespace=foo
(as a single query injection).Changes:
Related PRs: