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

internal/dag: Add exact path match condition in HttpProxy #5000

Merged
merged 13 commits into from
Apr 26, 2023

Conversation

arjunsalyan
Copy link
Contributor

This adds support for exact path matching in the HttpProxy along side prefix matching

fixes #4069
Signed-off-by: Arjun Salyan iarjunsalyan@gmail.com

@arjunsalyan arjunsalyan requested a review from a team as a code owner January 24, 2023 17:44
@arjunsalyan arjunsalyan requested review from tsaarni and sunjayBhatia and removed request for a team January 24, 2023 17:44
@github-actions
Copy link

Hi @arjunsalyan! Welcome to our community and thank you for opening your first Pull Request. Someone will review it soon. Thank you for committing to making Contour better. You can also join us on our mailing list and in our channel in the Kubernetes Slack Workspace

@arjunsalyan
Copy link
Contributor Author

This is by no means near completion. Still need to cover some edge cases as I feel I must have missed them, and work on the documentation. Any reviews and feedback would be very helpful. Also, please bear with me as this is my first PR.

Copy link
Member

@sunjayBhatia sunjayBhatia left a comment

Choose a reason for hiding this comment

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

re the rules around merging path conditions in the tree of HTTPProxy includes:

// If the root condition is prefix, and included condition is prefix then after merging we get one prefix condition.
// If the root condition is prefix, and included condition is exact then after merging we get one exact condition.
// If the root condition is exact, and included condition is exact then after merging we get one exact condition.
// If the root condition is exact, and included condition is prefix then after merging we get one prefix condition.

an alternate interpretation of the "exact" match in this context could be that such a match is terminal, i.e. it must come as a leaf of the tree of match conditions, since as it stands above if an exact match is at the root or middle of an include tree it effectively becomes a prefix match. if we want to keep these things distinct/clear that might be a way to go

@sunjayBhatia
Copy link
Member

Thanks for the PR @arjunsalyan I think this is a good start, but we will definitely need some more unit test coverage, we can give pointers where to look to add these if you like

we should already have logic further in our processing logic to sort the generated routes properly so that exact matches are considered by Envoy first, so this should mostly be covered by httpproxy processor/dag tests and some end to end tests

@arjunsalyan
Copy link
Contributor Author

arjunsalyan commented Feb 4, 2023

re the rules around merging path conditions in the tree of HTTPProxy includes:

// If the root condition is prefix, and included condition is prefix then after merging we get one prefix condition.
// If the root condition is prefix, and included condition is exact then after merging we get one exact condition.
// If the root condition is exact, and included condition is exact then after merging we get one exact condition.
// If the root condition is exact, and included condition is prefix then after merging we get one prefix condition.

an alternate interpretation of the "exact" match in this context could be that such a match is terminal, i.e. it must come as a leaf of the tree of match conditions, since as it stands above if an exact match is at the root or middle of an include tree it effectively becomes a prefix match. if we want to keep these things distinct/clear that might be a way to go

Agreed @sunjayBhatia, If you see the next line ahead of these comments I have mentioned the interpretation. These comments are just to explain why we reached the conclusion that the leaf decides the path type.

// Hence this can be concluded that the last rule in the delegation chain decides the path type

Will improve the wording of this statement. Let me know if you meant something else.

@sunjayBhatia
Copy link
Member

re the rules around merging path conditions in the tree of HTTPProxy includes:

// If the root condition is prefix, and included condition is prefix then after merging we get one prefix condition.
// If the root condition is prefix, and included condition is exact then after merging we get one exact condition.
// If the root condition is exact, and included condition is exact then after merging we get one exact condition.
// If the root condition is exact, and included condition is prefix then after merging we get one prefix condition.

an alternate interpretation of the "exact" match in this context could be that such a match is terminal, i.e. it must come as a leaf of the tree of match conditions, since as it stands above if an exact match is at the root or middle of an include tree it effectively becomes a prefix match. if we want to keep these things distinct/clear that might be a way to go

Agreed @sunjayBhatia, If you see the next line ahead of these comments I have mentioned the interpretation. These comments are just to explain why we reached the conclusion that the leaf decides the path type.

// Hence this can be concluded that the last rule in the delegation chain decides the path type

Will improve the wording of this statement. Let me know if you meant something else.

Above I meant that an option we can take is to not allow and mark an HTTPProxy as Invalid if you try to use an exact match in an include match condition

@arjunsalyan arjunsalyan force-pushed the httpproxy/exact-match branch 2 times, most recently from 823e20d to 3d26269 Compare February 7, 2023 08:12
@arjunsalyan
Copy link
Contributor Author

Above I meant that an option we can take is to not allow and mark an HTTPProxy as Invalid if you try to use an exact match in an include match condition

Got it. I have some subjective thoughts here, especially for the case of delegation of a path to teams. Included routes should have the flexibility to use exact matches. But open to any other views on this.

I have added unit tests and e2e trying to cover most of the things. Will start with documentation once these things come to good shape.

@arjunsalyan
Copy link
Contributor Author

For now I have added the docs considering my initial theory about routes delegation, just to make this PR ready for a review. Although we can revisit it.

@arjunsalyan arjunsalyan requested review from sunjayBhatia and removed request for tsaarni and skriss February 10, 2023 14:08
Copy link
Member

@sunjayBhatia sunjayBhatia left a comment

Choose a reason for hiding this comment

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

I think my interpretation of "Exact" path matching in conjunction with the Inclusion feature is that if you are using Inclusion, you really want a "Prefix" match (because the Included child proxy can then do different matching) so "Exact" matches should be disallowed on the path match conditions on an Include

cc @skriss @tsaarni if you have any thoughts

@skriss
Copy link
Member

skriss commented Mar 1, 2023

I think my interpretation of "Exact" path matching in conjunction with the Inclusion feature is that if you are using Inclusion, you really want a "Prefix" match (because the Included child proxy can then do different matching) so "Exact" matches should be disallowed on the path match conditions on an Include

cc @skriss @tsaarni if you have any thoughts

Yeah, that is how I had been thinking about it too, should be disallowed as an Include condition.

@arjunsalyan
Copy link
Contributor Author

I think my interpretation of "Exact" path matching in conjunction with the Inclusion feature is that if you are using Inclusion, you really want a "Prefix" match (because the Included child proxy can then do different matching) so "Exact" matches should be disallowed on the path match conditions on an Include
cc @skriss @tsaarni if you have any thoughts

Yeah, that is how I had been thinking about it too, should be disallowed as an Include condition.

Alright, I am starting to see the point here. But before we reach a conclusion, please allow me to put one last statement in the favour of the proposed merging algorithm.

  • Since we have a strict rule of one fqdn - one httpproxy, inclusion becomes the only way to route traffic to services in different namespaces from the same fqdn. To adopt a general approach, we currently follow a methodology where we create an orphan httpproxy without any rules in all of the namespaces. Then we create a root httpproxy in one of the namespaces and define all the rules in that root httpproxy. Not having the exact condition in include takes away this flexibility.

There are definitely other ways to handle this, but just putting a use case.

Anyways, I am now aligned on not allowing the Exact in the Include condition. Will push the changes soon.

@arjunsalyan arjunsalyan force-pushed the httpproxy/exact-match branch 2 times, most recently from 1dad0b2 to 29ccfcf Compare March 15, 2023 11:54
@arjunsalyan
Copy link
Contributor Author

Hi @skriss @sunjayBhatia

The changes for disallowing the exact condition except for the child/leaf httproxy are done.

@github-actions github-actions bot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Apr 4, 2023
@sunjayBhatia sunjayBhatia removed the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Apr 4, 2023
},
},
}
invalidRootProxy := &contourv1.HTTPProxy{
Copy link
Member

Choose a reason for hiding this comment

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

i think it's ok to omit testing this in e2e tests, should instead get coverage in the dag package tests

Paths defined are matched using exact conditions.
Up to one exact condition may be present in any condition block. Any condition block can
either have an exact condition or prefix condition, but not both together. Exact conditions are
not allowed in root httpproxies or in includes blocks.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
not allowed in root httpproxies or in includes blocks.
only allowed in route match conditions and not in include match conditions.

To resolve this Contour applies the following logic.

- `prefix:` conditions are concatenated together in the order they were applied from the root object. For example the conditions, `prefix: /api`, `prefix: /v1` becomes a single `prefix: /api/v1` conditions. Note: Multiple prefixes cannot be supplied on a single set of Route conditions.
- `exact:` conditions are also concatenated just like `prefix:` conditions, but `exact:` conditions are not allowed in the root httpproxy or in the inlcusion block. If the child httpproxy has `exact:` condition then after concatenation, it becomes a single `exact:` condition. For example, `prefix: /static` and `exact: /main.js` become a single `exact: /static/main.js` condition.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
- `exact:` conditions are also concatenated just like `prefix:` conditions, but `exact:` conditions are not allowed in the root httpproxy or in the inlcusion block. If the child httpproxy has `exact:` condition then after concatenation, it becomes a single `exact:` condition. For example, `prefix: /static` and `exact: /main.js` become a single `exact: /static/main.js` condition.
- `exact:` conditions are also concatenated just like `prefix:` conditions, but `exact:` conditions are not allowed in include match conditions. If the child httpproxy has `exact:` condition then after concatenation, it becomes a single `exact:` condition. For example, `prefix: /static` and `exact: /main.js` become a single `exact: /static/main.js` condition.

apis/projectcontour/v1/httpproxy.go Show resolved Hide resolved
internal/dag/httpproxy_processor.go Show resolved Hide resolved
internal/dag/httpproxy_processor.go Show resolved Hide resolved
internal/dag/httpproxy_processor.go Show resolved Hide resolved
@arjunsalyan
Copy link
Contributor Author

@sunjayBhatia Added the generated sources, which were leading to the failed test.

@arjunsalyan
Copy link
Contributor Author

This is strange

Build and Test Pull Request / test-linux (pull_request)
Build and Test Pull Request / test-osx (pull_request)

These tests pass all fine when I run them locally. Looking into it

@sunjayBhatia
Copy link
Member

This is strange

Build and Test Pull Request / test-linux (pull_request)
Build and Test Pull Request / test-osx (pull_request)

These tests pass all fine when I run them locally. Looking into it

you'll want to merge/rebase on main, and update the port in that test (github is merging the PR with the base branch when checking out the code)

This adds support for exact path matching in the HttpProxy along side
prefix matching

Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
…ical

Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
@arjunsalyan
Copy link
Contributor Author

arjunsalyan commented Apr 14, 2023

you'll want to merge/rebase on main, and update the port in that test (github is merging the PR with the base branch when checking out the code)

Ah! The tests were updated. Fixed, thanks.

@codecov
Copy link

codecov bot commented Apr 14, 2023

Codecov Report

Merging #5000 (b673ca1) into main (5b4f4eb) will increase coverage by 0.04%.
The diff coverage is 91.80%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #5000      +/-   ##
==========================================
+ Coverage   77.74%   77.79%   +0.04%     
==========================================
  Files         139      139              
  Lines       18073    18121      +48     
==========================================
+ Hits        14051    14097      +46     
- Misses       3750     3753       +3     
+ Partials      272      271       -1     
Impacted Files Coverage Δ
internal/dag/httpproxy_processor.go 92.27% <68.75%> (-0.07%) ⬇️
internal/dag/conditions.go 96.60% <100.00%> (+0.43%) ⬆️
internal/dag/dag.go 96.71% <100.00%> (+0.06%) ⬆️


f.CreateHTTPProxyAndWaitFor(serviceProxy, e2e.HTTPProxyValid)

cases := map[string]string{
Copy link
Member

Choose a reason for hiding this comment

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

nit: I think this looks correct, but it's not super intuitive to read

not a huge deal but would be nice to either add some comments above some of the cases or use naming of the routes/services that make it clearer

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can agree to that, it is just the nature of a few cases that I could not find better naming. Have tried something with comments, not sure how much value that adds though.

f.CreateHTTPProxyAndWaitFor(baseProxy, e2e.HTTPProxyValid)
f.CreateHTTPProxyAndWaitFor(invalidRootProxy, e2e.HTTPProxyInvalid)

cases := map[string]string{
Copy link
Member

Choose a reason for hiding this comment

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

similar nit to the above on comments/naming to make these test cases super clear (looks correct though)

@@ -14958,6 +15090,9 @@ func listeners(ls ...*Listener) []*Listener {
func prefixString(prefix string) MatchCondition {
return &PrefixMatchCondition{Prefix: prefix, PrefixMatchType: PrefixMatchString}
}
func exactString(exact string) MatchCondition {
Copy link
Member

Choose a reason for hiding this comment

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

nit: the prefixString was named since it represented a prefix match that would basically match a path using "string prefix" vs. matching path segments, we could change this to just exact 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.

Makes sense, rather exact() is already there making it completely redundant.

Copy link
Member

@sunjayBhatia sunjayBhatia left a comment

Choose a reason for hiding this comment

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

looks good overall, just some tiny nits

approving but will leave for another maintainer to have a pass over as well before merge

Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
exactString(exact string) is redundant and does the same as exact(path string)

Signed-off-by: Arjun Salyan <iarjunsalyan@gmail.com>
Copy link
Member

@skriss skriss 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 @arjunsalyan!

@skriss skriss merged commit 8946933 into projectcontour:main Apr 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-note/minor A minor change that needs about a paragraph of explanation in the release notes.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Exact path match for HTTPProxy
3 participants