-
Notifications
You must be signed in to change notification settings - Fork 743
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
Write location parser for Mutations #946
Conversation
@maxsmythe @fedepaol @ritazh @sozercan @brycecr here's a first go at the location parser. Also - this language needs a name. Let me know your thoughts! 🙂 |
be72fdb
to
d2fbc8c
Compare
Wasn't it the max's syntax :P ? |
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 a few comments
pkg/path/parser/parser.go
Outdated
err error | ||
} | ||
|
||
func NewParser(input string) *Parser { |
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.
From a consumer perspective, the flow will always be
p := NewParser("string")
p.Parse()
I think it would be better to have a single exported Parse
function that hides the parser.
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.
Sounds good!
pkg/path/token/scanner_test.go
Outdated
}, | ||
}, | ||
{ | ||
input: `"🤔☕️❗️"`, |
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.
:-)
pkg/path/parser/parser.go
Outdated
// expect returns whether the next token matches our expectation, | ||
// and if so advances to that token. | ||
// Otherwise returns false and doesn't advance. | ||
func (p *Parser) expect(t token.Type) bool { |
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.
The for loop below is a bit hard to get without reading this comment first.
Would it make sense to use only expectPeek
(and maybe change to something less "assertive" like peekMatches
) and explicitly advance via p.next() ?
Or even better, take the "peek" value and use it as the value to switch on? I think the result will be more understandable.
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.
Combining assertion with advancing through the tokens seems like a pattern that's out there, and combining that with optional matching felt like it streamlined the code and removed boilerplate.
I'm not married to this - but are there other ways of improving clarify? Can the function name be more descriptive? Can the comments be better, or would a description of the parser at the top help?
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 I think the thing that confused me the most was the hidden side effect of advancing when the expectation is matched. A comment before the switch, or a better name will probably make it clearer.
Now, the hard part is to find a decent name :-)
Something like advanceWhenNext
, or advanceIfNext
maybe. But I am also fine with adding a comment before the switch if we don't find a better alternative, I don't want this to be blocking.
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 this! Very clean.
re: Name
"Max's Syntax" <- ugh :p that'll either work real well or really poorly!
"Max's unplanned location-focused operator controls" -> Muloc?
"Shomron's Folly"? :p
"Put things here" -> PTH
"Yet another path language" -> YAPL
pkg/path/token/scanner.go
Outdated
} | ||
|
||
func isSpace(r rune) bool { | ||
return r == ' ' || r == '\t' |
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.
Should we also skip newlines?
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.
Easy enough.
pkg/path/token/scanner.go
Outdated
case ':': | ||
tok = Token{Type: COLON, Literal: string(s.ch)} | ||
case '"', '\'': | ||
tok.Type = IDENT |
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 IDENT
a well-known abbreviation? I think it means "identity" or "identifier" in this case?
Not sure that that is the most apt name given it can hold:
- A proper identifier in the form of a field name
- A value in the form of a key-field value
No better name is coming to mind though.
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.
IDENT
is short for identifier, and in this case means a name that is not a keyword. I've seen that shorthand in many parsers, for example here's a search across the go source.
Our language doesn't need to differentiate between a string and an identifier so I decide not to define a separate string token. Not sure whether it's textbook but it seemed to make sense at the time ¯_(ツ)_/¯
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.
SGTM, if we think of a better name we can change this later. literal
maybe? I don't love any of `em
pkg/path/token/scanner_test.go
Outdated
}, | ||
}, | ||
{ | ||
input: `Moo🐙`, |
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.
This should be a syntax error.
The octopus does NOT say moo
pkg/path/parser/parser_test.go
Outdated
}, | ||
}, | ||
{ | ||
// TODO: Is this useful or should we make it a parsing error? |
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.
IMO it's a parsing error.
I could see someone needing to reference a nil-valued var, would we be able to have a "nil" keyword?
Part of the reason for requiring quotes post-colon is to reserve the possibility of other special keywords.
Another option could be to have an anti-quote (e.g. a backtic) to signify "this value is a JS keyword"
pkg/path/parser/parser_test.go
Outdated
}, | ||
}, | ||
{ | ||
// TODO: Should this be allowed? |
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 should not be allowed. It's impossible to have a list-of-lists, as an intermediate object is required to store the key fields:
{
"spec": [
{
"myKey": "some-value",
"nestedList": [
{"secondKey": "secondValue"}
]
}
Note the need to access nestedList
4a60a4d
to
41b90ab
Compare
pkg/mutation/mutator.go
Outdated
"github.com/pkg/errors" | ||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
|
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: consolidate imports
return "", false | ||
} | ||
return *l.KeyValue, true | ||
} |
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.
The naming is a bit of what we have in the [interface design doc] (also the additional Path type)(https://docs.google.com/document/d/1c5Z3g6Zsfmga7xod4--t6RrXamdAaMaqYzPNujtZb10/edit?ts=5f98003c)
Can we either update the PR or the doc?
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.
Updated the doc
expectErr: true, | ||
}, | ||
{ | ||
// List cannot follow valid list |
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.
Do we also want to check pathentries that end in a globbed list? That should also be disallowed, as then we would be setting multiple objects to the exact same 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.
Hmm - I'm not sure that be a parse error, but perhaps a validation to apply at a higher level?
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.
That's a fair thought, I think the path tests will allow glob-terminated locations.
5421857
to
3f293c2
Compare
Codecov Report
@@ Coverage Diff @@
## master #946 +/- ##
==========================================
+ Coverage 43.57% 45.76% +2.18%
==========================================
Files 52 56 +4
Lines 3222 3374 +152
==========================================
+ Hits 1404 1544 +140
- Misses 1622 1634 +12
Partials 196 196
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
I think I've incorporated all feedback - let me know if there's any other changes pending. |
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, letting this sit overnight in case @fedepaol has any more feedback.
Sounds good - thank you for the thorough review! |
pkg/mutation/path/parser/parser.go
Outdated
return p.peekToken.Type == t | ||
} | ||
|
||
func (p *Parser) Parse() (*Path, error) { |
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: this can be private?
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'll keep the method exported in case the parser is exported in the future. It is the public-facing interface to the parser, even if the parser is not public.
pkg/mutation/path/parser/parser.go
Outdated
"github.com/open-policy-agent/gatekeeper/pkg/mutation/path/token" | ||
) | ||
|
||
type Parser struct { |
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: can be the parser private?
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.
Sure, fixed in latest commit.
Just a comment about the visibility of the parser. |
dfc2df4
to
1d20dbf
Compare
The location parser parses the location specification language used for matching Kubernetes object fields. Example: ``` p := NewParser("spec.containers[name:*].securityContext") root, err := p.Parse() ... Closes open-policy-agent#915 Signed-off-by: Oren Shomron <shomron@gmail.com>
Signed-off-by: Oren Shomron <shomron@gmail.com>
* Relocated location parser under pkg/mutation * Rename Object.Value -> Object.Reference * Rename Root -> Path * Support newlines as whitespace * Disallow listSpec that does not follow object path segment * In listSpec, disallow nil fieldValue if glob is not specified * Octopus can still say Moo Signed-off-by: Oren Shomron <shomron@gmail.com>
Signed-off-by: Oren Shomron <shomron@gmail.com>
The parser functionality is exposed behind the Parse function. The parser struct itself is not currently needed outside the package, so we will unexport it for now. Signed-off-by: Oren Shomron <shomron@gmail.com>
1d20dbf
to
15cb728
Compare
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.
lgtm
The location parser parses the location specification language used
for matching Kubernetes object fields.
Example:
Closes #915
Signed-off-by: Oren Shomron shomron@gmail.com