Skip to content

feat: watch resource with selectors#1661

Merged
Alice-Lilith merged 33 commits intoenvoyproxy:mainfrom
den3tsou:watch-resource-with-selector
Sep 12, 2023
Merged

feat: watch resource with selectors#1661
Alice-Lilith merged 33 commits intoenvoyproxy:mainfrom
den3tsou:watch-resource-with-selector

Conversation

@den3tsou
Copy link
Copy Markdown
Contributor

What this PR does / why we need it:
This PR is to provides a handy way for users to watch namespaces with certain labels. Envoy Gateway currently only supports specifying namespaces to watch which is not convenient for users.

Add namespaceSelectors watch mode for Kubernetes provider. Users will need to specify EnvoyGateway.Provider.Type and precisely one of EnvoyGateway.Provider.Kubernetes.Wach.Namespaces and EnvoyGateway.Provider.Kubernetes.Wach.NamespaceSelectors to set the KuberNtes wach mode.

The namespaceSelectors doesn't change the namespace informers watch. The informer still watches all namespaces. The events which have Objects that are not under namesapces with the labels set by NamespaceSelectors are filtered out.

Which issue(s) this PR fixes:
Fixes #1622

@den3tsou den3tsou requested a review from a team as a code owner July 16, 2023 00:03
Add namespaceSelectors watch mode for Kubernetes provider. Users will
need to specify `EnvoyGateway.Provider.Type` and precisely one of
`EnvoyGateway.Provider.Kubernetes.Wach.Namespaces` and
`EnvoyGateway.Provider.Kubernetes.Wach.NamespaceSelectors` to set the
KuberNtes wach mode.

The namespaceSelectors doesn't change the namespace informers watch. The
informer still watches all namespaces. The events which have Objects that
are not under namesapces with the labels set by `NamespaceSelectors` are
filtered out.

Signed-off-by: Den Tsou <den3tsou@gmail.com>
}

if svr.EnvoyGateway.Provider != nil &&
// TODO: implment config validatoin on the watch mode config
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There doesn't seem to be any validation in place. Do I need to add it in this PR?

},
ns,
); err != nil {
// Question: what's the common practice to handle error in predicate?
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Could anyone help me to understand the common practices in Enovy Gateway to handle errors in predicate?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logging an error and returning false is fine


// TestGatewayClassHasMatchingNamespaceLabels tests the hasMatchingNamespaceLabels
// predicate function.
func TestGatewayClassHasMatchingNamespaceLabels(t *testing.T) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is this the only place to add tests? Do I need to add tests anywhere else?

Copy link
Copy Markdown
Contributor

@arkodg arkodg Jul 18, 2023

Choose a reason for hiding this comment

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

a good end to end test to add would be to implement this example https://gateway-api.sigs.k8s.io/guides/multiple-ns/ in our e2e https://github.com/envoyproxy/gateway/tree/main/test/e2e/tests
and ensure above traffic path works

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @arkodg, would you please help me understand how to test the predicate behaviour with e2e tests? Is there any API I could hit in order to know that certain events are filtered out?

Copy link
Copy Markdown
Contributor

@arkodg arkodg Jul 26, 2023

Choose a reason for hiding this comment

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

based on https://gateway-api.sigs.k8s.io/guides/multiple-ns/#shared-gateway you could ensure e2e routing works when default ns has label shared-gateway-access: "true" set and fails when it is not set

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @arkodg, this is doable but difficult. There is no easy way to reconfig Envoy Gateway in the current testing structure inlcuding 1) apply new ConfigMap 2) restart Envoy Gateway which is needed for this test. Adding those changes will make this PR too big. What's your thoughts on this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @arkodg This is a bit tricky. I will share what I've found, so you could help me to brainstorm some ideas.

There are two approach available at this moment

  • Initialise the k8s client to obtain all namespaces with certain labels
    • Pros:
      • No complex change for reconciler because configuring Manager is enough
    • Cons:
      • Users need to restart Envoy Gateway controller every time they add update the namespaces unless there is another goroutine or anything similar to check the namespace regularly and update the Manger config accordingly
  • Use predicate and update all of logic inside reconciler to check if the objects' namespaces have certain labels
    • Pros:
      • Users don't need to redeploy Envoy Gateway controller every time they update namespaces
    • Cons:
      • All logic inside reconciler uses manager.client needs to have additional logic to check if the objects are under namepsace with certain labels. This may cause performance issue because every object will need to be checked.

These two solutions are what I've found so far. I've checked the controller-runtime to see if it has any features that I could workaround. Unfortunately, I coudln't find any solutions yet. Do you have any ideas?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @arkodg , any update on this. I am fine to decline this PR and work on other tasks. I've spent fair bit of time finding other solution. But this is more related to how reconciler works, there is no work around for it. All of code related to pull data from api server will need to be updated.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I vote for Use predicate and update all of logic inside reconciler to check if the objects' namespaces have certain labels . The con here is the extra Get of the Namespace which is hopefully cached and shouldnt be expensive, another con is logic complexity, but counting on you to max code reuse :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks 👍 . I will start to implement it :-D

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @arkodg , do you mind having a look and giving some early feedback? I am still working out how to add tests to make sure all places with the namespace labels check are covered.

den3tsou added 2 commits July 17, 2023 21:35
Signed-off-by: Den Tsou <den3tsou@gmail.com>
Signed-off-by: Den Tsou <den3tsou@gmail.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Jul 19, 2023

Codecov Report

Merging #1661 (4e27b7c) into main (31ea531) will increase coverage by 0.69%.
The diff coverage is 70.48%.

@@            Coverage Diff             @@
##             main    #1661      +/-   ##
==========================================
+ Coverage   65.36%   66.06%   +0.69%     
==========================================
  Files          86       86              
  Lines       12529    12829     +300     
==========================================
+ Hits         8190     8475     +285     
+ Misses       3822     3821       -1     
- Partials      517      533      +16     
Files Changed Coverage Δ
internal/provider/kubernetes/filters.go 52.30% <54.16%> (-4.22%) ⬇️
internal/provider/kubernetes/predicates.go 54.78% <59.37%> (+0.84%) ⬆️
internal/provider/kubernetes/routes.go 56.00% <73.33%> (+12.27%) ⬆️
internal/provider/kubernetes/controller.go 55.75% <78.10%> (+6.61%) ⬆️
internal/provider/kubernetes/kubernetes.go 69.64% <100.00%> (+2.33%) ⬆️

... and 1 file with indirect coverage changes

@arkodg arkodg added this to the 0.6.0-rc1 milestone Jul 27, 2023
den3tsou and others added 11 commits July 31, 2023 21:36
* This is a protytpe. Refactoring is required to make the code more
readable because the code is getting more complex after adding this
logic
* Update to check all labels of namespaces of objects returned by client
* Fix a bug that wrong type was checked
* Don't apply predicate to filter out the event related to GatewayClass
  because GatewayClass is cluster scoped object
* Simple test to check if only certain number of gateway is returned.
  More test logic is indeed needed to be added

Signed-off-by: Den Tsou <den3tsou@gmail.com>
Signed-off-by: Den Tsou <den3tsou@gmail.com>
Signed-off-by: Den <6628668+den3tsou@users.noreply.github.com>
Signed-off-by: Den Tsou <den3tsou@gmail.com>
Signed-off-by: Den Tsou <den3tsou@gmail.com>
Signed-off-by: Den Tsou <den3tsou@gmail.com>
// Type indicates what watch mode to use. KubernetesWatchModeTypeNamespaces and
// KubernetesWatchModeTypeNamespaceSelectors are currently supported
// By default, when this field is unset or empty, Envoy Gateway will watch for input namespaced resources
// from all namespaces.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

needs a default tag here similar to

// +kubebuilder:default=Replace

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Do I miss anything here? This is an optional field. It has to be defined with either Namespaces or NamespaceSelectors

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @arkodg, do you mind helping me understand this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this should be // +kubebuilder:default=Namespaces

}

for _, udpRoute := range udpRouteList.Items {
udpRoutes := udpRouteList.Items
Copy link
Copy Markdown
Contributor

@arkodg arkodg Aug 24, 2023

Choose a reason for hiding this comment

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

can all this code be consolidated/reused across all resource types by using a helper func with a client.Object signature ?

Copy link
Copy Markdown
Contributor Author

@den3tsou den3tsou Aug 26, 2023

Choose a reason for hiding this comment

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

ahhh. Good catch. I didn't realise that client.Object could be used!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately, AuthenticaionFilter, RateLimitFilterandunstructured.Unstructured` don't implment the common interface. The alternative I could do is to add a NamespaceGetter interface to simplify the code.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you could use existing code for them, and add a TODO

ok, err := r.checkNamespaceLabels(ns)
if err != nil {
r.log.Error(
err, "fail to get Namespace",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
err, "fail to get Namespace",
err, "failed to get Namespace labels",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

predicate.ResourceVersionChangedPredicate{},
predicate.NewPredicateFuncs(r.hasManagedClass),
}
if len(ls) != 0 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why is ls needed here, can't you just use r.namespaceLabels as a way to check

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

good catch. updated

den3tsou and others added 8 commits August 28, 2023 16:55
* Update hasMatchingNamespaceLabels signature because labels is part of
  the struct field now
* Remove the logic to check namespace of certificate ref because it is
  not necessary
* Refactor the checkNamespaceLabels with new interface, so the code is
  more readable now

Signed-off-by: Den Tsou <den3tsou@gmail.com>
Signed-off-by: Den Tsou <den3tsou@gmail.com>
Signed-off-by: Den Tsou <den3tsou@gmail.com>
Signed-off-by: Den <6628668+den3tsou@users.noreply.github.com>
Signed-off-by: Den Tsou <den3tsou@gmail.com>
Signed-off-by: Den Tsou <den3tsou@gmail.com>
@den3tsou
Copy link
Copy Markdown
Contributor Author

den3tsou commented Sep 3, 2023

Hi @arkodg , I finally complete the integration tests. Would you please have a look again?

Copy link
Copy Markdown
Contributor

@arkodg arkodg left a comment

Choose a reason for hiding this comment

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

one nit, else looks good, thanks @den3tsou !

@arkodg
Copy link
Copy Markdown
Contributor

arkodg commented Sep 12, 2023

lets merge this one after #1534 has merged to reduce conflicts

@arkodg arkodg requested review from a team, LanceEa, chauhanshubham and kflynn and removed request for a team September 12, 2023 20:56
Copy link
Copy Markdown
Member

@Alice-Lilith Alice-Lilith left a comment

Choose a reason for hiding this comment

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

lgtm. @arkodg I see no conflicts after merging #1534 so I'm gonna go ahead and merge this now to prevent additional churn on this PR. Any outstanding nits can be resolved via a follow-up PR.

@Alice-Lilith Alice-Lilith merged commit 373ef32 into envoyproxy:main Sep 12, 2023
@den3tsou den3tsou deleted the watch-resource-with-selector branch September 13, 2023 08:09
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.

watch resource with selector

4 participants