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
Convert EndpointSlice Reconciler to a library in staging. #118953
Conversation
This issue is currently awaiting triage. If a SIG or subproject determines this is a relevant issue, they will accept it by applying the The Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
@@ -85,7 +85,7 @@ func NewPortMapKey(endpointPorts []discovery.EndpointPort) PortMapKey { | |||
// DeepHashObjectToString creates a unique hash string from a go object. | |||
func DeepHashObjectToString(objectToWrite interface{}) 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.
The only other consumer of this is util/endpointslice
. I wonder if it makes sense to combine k8s.io/endpointslice/util/endpoint
and k8s.io/endpointslice/util/endpointslice
into k8s.io/endpointslice/util
to reduce the public API surface.
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.
Maybe even flatten k8s.io/endpointslice/util
into k8s.io/endpointslice
? Looking at some of the functions like ShouldPodBeInEndpoints
, I think they belong in the main pkg. See https://www.kubernetes.dev/docs/guide/coding-convention/#directory-and-file-conventions:
Avoid general utility packages. Packages called “util” are suspect.
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.
yeah, it does not make have much sense have so many utils folders, in theory k8s.io/endpointslice/util/endpoint
should only be used for the endpoints controller, but I'm not surprised we ended mixing things
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 we have to limit ourselves to k8s.io/endpointslice/util, since k8s.io/endpointslice/topologycache
and k8s.io/endpointslice/metrics
import utils as well, and if not mistaken, we will end up with cyclic imports
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 looks like k8s.io/endpointslice/topologycache
no longer depends on k8s.io/endpointslice/util
, and only k8s.io/endpointslice/metrics
does. But now I'm wondering whether metrics
should be flattened into k8s.io/endpointslice
as well ..
Is there any value in having metrics be a separate module? It's only really used by the reconciler and doesn't seem like it can be reused anywhere else. This would let us reduce the API surface substantially.
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.
There are a bunch of /util
functions that are only used within k8s.io/endpointslice
(incl. metrics
and topologycache
) but they're part of the public API. Instead of flattening, maybe a better approach is to move those functions into /internal
instead?
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.
metrics
is used in the controller e.g. https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/endpointslice/endpointslice_controller.go#L564
staging/src/k8s.io/endpointslice/util/endpoint/controller_utils.go
Outdated
Show resolved
Hide resolved
printer.Fprintf(hasher, "%#v", objectToWrite) | ||
} | ||
|
||
func IsPodReady(pod *v1.Pod) 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.
If we flatten the relevant utils into k8s.io/endpointslice
, then this can be made 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.
staging/src/k8s.io/endpointslice/util/endpoint/controller_utils.go
Outdated
Show resolved
Hide resolved
@@ -38,10 +38,10 @@ import ( | |||
"k8s.io/client-go/tools/cache" | |||
"k8s.io/client-go/tools/record" | |||
"k8s.io/client-go/util/workqueue" | |||
endpointsliceutil "k8s.io/endpointslice/util/endpointslice" |
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 unfortunate that the EndpointSlice reconciler library is not sufficiently generic to be used by the EndpointSlice Mirroring controller. Although it's out of scope for this PR, it would probably be good to document somewhere, either in the EndpointSlice mirroring controller or in the new EndpointSlice staging lib why that is. I believe it comes down to the fact that the reconciler in the EndpointSlice mirroring controller has a 1:1 mapping between Service/Endpoints and EndpointSlice, which results in a simpler implementation that the EndpointSlice staging lib.
Now that the code is in a place that it could be shared, we probably want to at least describe why it's not currently shared, and state that contributions to move towards the shared code being used by the mirroring controller would be welcome.
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.
not sure it is the right place, but added above to the README.
@@ -62,7 +61,7 @@ func GetPodServiceMemberships(serviceLister v1listers.ServiceLister, pod *v1.Pod | |||
// if the service has a nil selector this means selectors match nothing, not everything. | |||
continue | |||
} | |||
key, err := controller.KeyFunc(service) | |||
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(service) |
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.
Interesting, I think that this is not needed at all, but I leave this just as a comment to not forget and revisit later https://github.com/kubernetes/kubernetes/pull/84280/files#r1247603063, no action required
} | ||
|
||
// IsPodReady returns true if Pods Ready condition is true | ||
// copied from k8s.io/kubernetes/pkg/api/v1/pod |
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.
@thockin @BenTheElder do you know some magic to keep these things in sync?
some linter maybe?
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.
no, I don't have a good answer. Most of them are API based, and we won't intentionally break that, so it's another case "a little copy is better than a little dep", probably.
pull-kubernetes-verify jobs failures are legit, something with the rules and restrictions, I'm not very familiar with this to be able to pinpoint the problem
/test pull-kubernetes-node-e2e-containerd the rest looks pretty nice, right? |
|
||
// EndpointReady returns true if an Endpoint has the Ready condition set to | ||
// true. | ||
func EndpointReady(endpoint discovery.Endpoint) 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.
Can this be a private function? This shouldn't really be part of the public API.
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 is used in the reconciler 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.
Can it be private and copied to the call sites? It's a fairly trivial function. EndpointReady
really has nothing to do with topologycache
.
@@ -85,7 +85,7 @@ func NewPortMapKey(endpointPorts []discovery.EndpointPort) PortMapKey { | |||
// DeepHashObjectToString creates a unique hash string from a go object. | |||
func DeepHashObjectToString(objectToWrite interface{}) 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.
It looks like k8s.io/endpointslice/topologycache
no longer depends on k8s.io/endpointslice/util
, and only k8s.io/endpointslice/metrics
does. But now I'm wondering whether metrics
should be flattened into k8s.io/endpointslice
as well ..
Is there any value in having metrics be a separate module? It's only really used by the reconciler and doesn't seem like it can be reused anywhere else. This would let us reduce the API surface substantially.
@@ -354,7 +355,7 @@ func (c *Controller) syncService(key string) error { | |||
|
|||
esLabelSelector := labels.Set(map[string]string{ | |||
discovery.LabelServiceName: service.Name, | |||
discovery.LabelManagedBy: controllerName, | |||
discovery.LabelManagedBy: c.reconciler.GetControllerName(), |
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 use controllerName
directly here. Would eliminate the need for the GetControllerName
function.
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 want to expose controllerName.
|
||
// ManagedByChanged returns true if one of the provided EndpointSlices is | ||
// managed by the EndpointSlice controller while the other is not. | ||
func (r *Reconciler) ManagedByChanged(endpointSlice1, endpointSlice2 *discovery.EndpointSlice) 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.
Can be moved to pkg/controller/endpointslice/endpointslice_controller.go
and made private. It's only used there.
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.
you want to have that function as library, to identify if the particular object is managed by this controller.
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.
yeah, I can see how this can be useful for external consumers
|
||
// ManagedByController returns true if the controller of the provided | ||
// EndpointSlices is the EndpointSlice controller. | ||
func (r *Reconciler) ManagedByController(endpointSlice *discovery.EndpointSlice) 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.
Same as above. Can be moved to pkg/controller/endpointslice/endpointslice_controller.go
and made 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.
same comment as above, you want to have that function as library, to identify if the particular object is managed by this controller.
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.
agree with Maciej
/test pull-kubernetes-integration |
/assign @robscott |
/test pull-kubernetes-unit |
/test pull-kubernetes-unit |
failure is legit
|
/lgtm |
LGTM label has been added. Git tree hash: b97ff1a21421fe675f898cf34e46eaa9e6534853
|
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!
/lgtm
/approve
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: aojea, mskrocki, thockin The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
The Kubernetes project has merge-blocking tests that are currently too flaky to consistently pass. This bot retests PRs for certain kubernetes repos according to the following rules:
You can:
/retest |
@mskrocki: The following test failed, say
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
What type of PR is this?
/kind feature
What this PR does / why we need it:
See KEP-3685
Which issue(s) this PR fixes:
Fixes (kubernetes/enhancements#3685)
Special notes for your reviewer:
SIG-ARCH approval for new staging repo: https://groups.google.com/g/kubernetes-sig-architecture/c/Myu9NPxjp9U
Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: