Change:
If I modify a custom endpoint, the kubectl annotation is mirrored to the generated endpoint slice Since the kubect last-applied-configuration tracks the status of the object, it shouldn't be mirrored since it doesn't apply to the generated object a custom endpoint an update on any of the fields the generated endpoint slice annotations /sig network
ping
if we agree this is a bug, the fix is just and adding some tests of course :)
Thanks for catching this! Agree this is a bug that we should fix.
/triage accepted
/good-first-issue
This request has been marked as suitable for new contributors. Please ensure the request meets the requirements listed . If this request no longer meets these requirements, the label can be removed by commenting with the command. <detailsIn response to : /good-first-issue Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
Hey, I'm on it!
Hi While I have made the update mentioned in the above comment, I feel a bit lost on where to add/update tests. I understand that I probably shouldn't raise a PR without trying to add a few tests for this issue. So could you possibly guide me to the correct files(s) I should be looking into where the annotations for updated EndpointSlices are being tested?
Hey I think the easiest place to add tests might be here: You could add another test case where the Endpoints object had this label and then ensure that label was not copied over to an EndpointSlice.
Alright I'll check out these tests. Thank you!
/assign

Discussion:
// if >0 existing slices, mark all but 1 for deletion. slices.toDelete = existingSlices[1:] <del> // generated slices must mirror all endpoints annotations but EndpointsLastChangeTriggerTime compareAnnotations := cloneAndRemoveKeys(endpoints.Annotations, corev1.EndpointsLastChangeTriggerTime) </del> <ins> // generated slices must mirror all endpoints annotations but EndpointsLastChangeTriggerTime and LastAppliedConfigAnnotation compareAnnotations := cloneAndRemoveKeys(endpoints.Annotations, corev1.EndpointsLastChangeTriggerTime, corev1.LastAppliedConfigAnnotation) </ins> compareLabels := cloneAndRemoveKeys(existingSlices[0].Labels, discovery.LabelManagedBy, discovery.LabelServiceName) // Return early if first slice matches desired endpoints, labels and annotations totals = totalChanges(existingSlices[0], desiredSet)

testName                 string subsets                  []corev1.EndpointSubset epLabels                 map[string]string <ins> epAnnotations            map[string]string </ins> endpointsDeletionPending bool maxEndpointsPerSubset    int32 existingEndpointSlices   []*discovery.EndpointSlice

expectedClientActions:  2, maxEndpointsPerSubset:  2, expectedMetrics:        &expectedMetrics{desiredSlices: 2, actualSlices: 2, desiredEndpoints: 4, addedPerSync: 4, updatedPerSync: 0, removedPerSync: 0, skippedPerSync: 1, numCreated: 2, numUpdated: 0}, <ins> }, { testName: "The last-applied-configuration annotation should not get mirrored to created or updated endpoint slices", epAnnotations: map[string]string{ corev1.LastAppliedConfigAnnotation: "{"apiVersion":"v1","kind":"Endpoints","subsets":[]}", }, subsets: []corev1.EndpointSubset{{ Ports: []corev1.EndpointPort{{ Name:     "http", Port:     80, Protocol: corev1.ProtocolTCP, }}, Addresses: []corev1.EndpointAddress{{ IP:       "10.0.0.1", Hostname: "pod-1", }}, }}, existingEndpointSlices: []*discovery.EndpointSlice{}, expectedNumSlices:      1, expectedClientActions:  1, expectedMetrics:        &expectedMetrics{addedPerSync: 1, numCreated: 1, desiredEndpoints: 1, desiredSlices: 1, actualSlices: 1}, }, { testName: "The last-applied-configuration annotation shouldn't get added to created endpoint slices", subsets: []corev1.EndpointSubset{{ Ports: []corev1.EndpointPort{{ Name:     "http", Port:     80, Protocol: corev1.ProtocolTCP, }}, Addresses: []corev1.EndpointAddress{{ IP:       "10.0.0.1", Hostname: "pod-1", }}, }}, existingEndpointSlices: []*discovery.EndpointSlice{}, expectedNumSlices:      1, expectedClientActions:  1, expectedMetrics:        &expectedMetrics{addedPerSync: 1, numCreated: 1, desiredEndpoints: 1, desiredSlices: 1, actualSlices: 1}, }, { testName: "The last-applied-configuration shouldn't get mirrored to endpoint slices when it's value is empty", epAnnotations: map[string]string{ corev1.LastAppliedConfigAnnotation: "", }, subsets: []corev1.EndpointSubset{{ Ports: []corev1.EndpointPort{{ Name:     "http", Port:     80, Protocol: corev1.ProtocolTCP, }}, Addresses: []corev1.EndpointAddress{{ IP:       "10.0.0.1", Hostname: "pod-1", }}, }}, existingEndpointSlices: []*discovery.EndpointSlice{}, expectedNumSlices:      1, expectedClientActions:  1, expectedMetrics:        &expectedMetrics{addedPerSync: 1, numCreated: 1, desiredEndpoints: 1, desiredSlices: 1, actualSlices: 1}, }, { testName: "Annotations other than last-applied-configuration should get correctly mirrored", epAnnotations: map[string]string{ corev1.LastAppliedConfigAnnotation: "{"apiVersion":"v1","kind":"Endpoints","subsets":[]}", "foo":                              "bar", }, subsets: []corev1.EndpointSubset{{ Ports: []corev1.EndpointPort{{ Name:     "http", Port:     80, Protocol: corev1.ProtocolTCP, }}, Addresses: []corev1.EndpointAddress{{ IP:       "10.0.0.1", Hostname: "pod-1", }}, }}, existingEndpointSlices: []*discovery.EndpointSlice{}, expectedNumSlices:      1, expectedClientActions:  1, expectedMetrics:        &expectedMetrics{addedPerSync: 1, numCreated: 1, desiredEndpoints: 1, desiredSlices: 1, actualSlices: 1}, }, { testName: "Annotation mirroring should remove the last-applied-configuration annotation from existing endpoint slices", subsets: []corev1.EndpointSubset{{ Ports: []corev1.EndpointPort{{ Name:     "http", Port:     80, Protocol: corev1.ProtocolTCP, }}, Addresses: []corev1.EndpointAddress{{ IP:       "10.0.0.1", Hostname: "pod-1", }}, }}, existingEndpointSlices: []*discovery.EndpointSlice{{ ObjectMeta: metav1.ObjectMeta{ Name: "test-ep-1", Annotations: map[string]string{ corev1.LastAppliedConfigAnnotation: "{"apiVersion":"v1","kind":"Endpoints","subsets":[]}", }, }, AddressType: discovery.AddressTypeIPv4, Ports: []discovery.EndpointPort{{ Name:     utilpointer.StringPtr("http"), Port:     utilpointer.Int32Ptr(80), Protocol: &protoTCP, }}, Endpoints: []discovery.Endpoint{{ Addresses:  []string{"10.0.0.1"}, Hostname:   utilpointer.StringPtr("pod-1"), Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)}, }}, }}, expectedNumSlices:     1, expectedClientActions: 1, </ins> }} for _, tc := range testCases {

setupMetrics() namespace := "test" endpoints := corev1.Endpoints{ <del> ObjectMeta: metav1.ObjectMeta{Name: "test-ep", Namespace: namespace, Labels: tc.epLabels}, </del> <ins> ObjectMeta: metav1.ObjectMeta{Name: "test-ep", Namespace: namespace, Labels: tc.epLabels, Annotations: tc.epAnnotations}, </ins> Subsets:    tc.subsets, }

if serviceNameVal != endpoints.Name { t.Errorf("Expected EndpointSlice to have %s label set to %s, got %s", discovery.LabelServiceName, endpoints.Name, serviceNameVal) } <ins> _, ok = epSlice.Annotations[corev1.LastAppliedConfigAnnotation] if ok { t.Errorf("Expected LastAppliedConfigAnnotation to be unset, got %s", epSlice.Annotations[corev1.LastAppliedConfigAnnotation]) } _, ok = epSlice.Annotations[corev1.EndpointsLastChangeTriggerTime] if ok { t.Errorf("Expected EndpointsLastChangeTriggerTime to be unset, got %s", epSlice.Annotations[corev1.EndpointsLastChangeTriggerTime]) } for annotation, val := range endpoints.Annotations { if annotation == corev1.EndpointsLastChangeTriggerTime || annotation == corev1.LastAppliedConfigAnnotation { continue } if epSlice.Annotations[annotation] != val { t.Errorf("Expected endpoint annotation %s to be mirrored correctly, got %s", annotation, epSlice.Annotations[annotation]) } } </ins> } for _, epSubset := range endpoints.Subsets {

epSlice.Labels[discovery.LabelServiceName] = endpoints.Name epSlice.Labels[discovery.LabelManagedBy] = controllerName <del> // clone all annotations but EndpointsLastChangeTriggerTime </del> <ins> // clone all annotations but EndpointsLastChangeTriggerTime and LastAppliedConfigAnnotation </ins> for annotation, val := range endpoints.Annotations { <del> if annotation == corev1.EndpointsLastChangeTriggerTime { </del> <ins> if annotation == corev1.EndpointsLastChangeTriggerTime || annotation == corev1.LastAppliedConfigAnnotation { </ins> continue } epSlice.Annotations[annotation] = val