Skip to content

KubernetesCatalogWatch.catalogServicesWatch throws an NPE when endpointslices are not set #1971

@Sjoerd97

Description

@Sjoerd97

We would like to upgrade to kubernetes version 1.33 and are therefor making a conscious effort to ditch endpoints in favour of endpointslices. Since we also use Keda in our cluster to scale our pods sometimes all the way to zero not all endpoints in the endpointslices object are always set. You would expect Spring cloud to handle this properly by filtering out empty endpoint slices. Yet I get a NPE whenever all endpoint slices are being retrieved

I was able to replicate the issue with the following test

`
import io.fabric8.kubernetes.api.model.ObjectReference;
import io.fabric8.kubernetes.api.model.discovery.v1.Endpoint;
import io.fabric8.kubernetes.api.model.discovery.v1.EndpointConditions;
import io.fabric8.kubernetes.api.model.discovery.v1.EndpointHints;
import io.fabric8.kubernetes.api.model.discovery.v1.EndpointSlice;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace;
import static java.util.Comparator.comparing;
import static java.util.Comparator.nullsLast;

public class Debugtest {

@Test
void check() {


    var endpointSlice1 = new EndpointSlice("IPv4", "discovery.k8s.io/v1", null, "EndpointSlice" , null, null);
    var endpointSlice2 = new EndpointSlice("IPv4", "discovery.k8s.io/v1",
                                                                                         List.of(new Endpoint(List.of("192.168.0.0"),
                                                  new EndpointConditions(true, true, true),
                                                  Map.of("key", "val"),
                                                  new EndpointHints(),
                                                  "hostName", "nodeName",
                                                  new ObjectReference("discovery.k8s.io/v1", "*/", "pod", "name!!!", "nameSpace!!!!", "", ""), "zone")), "EndpointSlice" , null, null);



    List<EndpointSlice> list = List.of(endpointSlice1, endpointSlice2);

    Stream<ObjectReference> references = list.stream()
            .map(EndpointSlice::getEndpoints)
            .flatMap(List::stream)
            .map(Endpoint::getTargetRef);

    var resList = references.filter(Objects::nonNull)
            .map(x -> new EndpointNameAndNamespace(x.getName(), x.getNamespace()))
            .sorted(comparing(EndpointNameAndNamespace::endpointName, nullsLast(String::compareTo)))
            .toList();

}

}
`

The test consist of a slice where there is no endpoints object and one where there is.
I was able to confirm that this scenario was equals to the our scenario during runtime.

A very easy way around this would be:

Stream<ObjectReference> references = list.stream() .map(EndpointSlice::getEndpoints) .filter(Objects::nonNull) .flatMap(List::stream) .map(Endpoint::getTargetRef);

This filters out everything in the stream that has no Endpoint.

I am also wondering why this isnt handle with Optionals?
That would have prevented the issue from happening all together

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Done

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions