mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 03:11:40 +00:00
Merge pull request #113351 from andrewsykim/endpointslice-terminating-ga
Promote EndpointSliceTerminatingCondition to GA
This commit is contained in:
commit
b20ddbd75a
4
api/openapi-spec/swagger.json
generated
4
api/openapi-spec/swagger.json
generated
@ -9629,11 +9629,11 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"serving": {
|
"serving": {
|
||||||
"description": "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
"description": "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"terminating": {
|
"terminating": {
|
||||||
"description": "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
"description": "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -107,11 +107,11 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"serving": {
|
"serving": {
|
||||||
"description": "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
"description": "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"terminating": {
|
"terminating": {
|
||||||
"description": "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
"description": "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -118,15 +118,13 @@ type EndpointConditions struct {
|
|||||||
// serving is identical to ready except that it is set regardless of the
|
// serving is identical to ready except that it is set regardless of the
|
||||||
// terminating state of endpoints. This condition should be set to true for
|
// terminating state of endpoints. This condition should be set to true for
|
||||||
// a ready endpoint that is terminating. If nil, consumers should defer to
|
// a ready endpoint that is terminating. If nil, consumers should defer to
|
||||||
// the ready condition. This field can be enabled with the
|
// the ready condition.
|
||||||
// EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Serving *bool
|
Serving *bool
|
||||||
|
|
||||||
// terminating indicates that this endpoint is terminating. A nil value
|
// terminating indicates that this endpoint is terminating. A nil value
|
||||||
// indicates an unknown state. Consumers should interpret this unknown state
|
// indicates an unknown state. Consumers should interpret this unknown state
|
||||||
// to mean that the endpoint is not terminating. This field can be enabled
|
// to mean that the endpoint is not terminating.
|
||||||
// with the EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Terminating *bool
|
Terminating *bool
|
||||||
}
|
}
|
||||||
|
@ -35,17 +35,14 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/apimachinery/pkg/util/rand"
|
"k8s.io/apimachinery/pkg/util/rand"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
k8stesting "k8s.io/client-go/testing"
|
k8stesting "k8s.io/client-go/testing"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/controller/endpointslice/topologycache"
|
"k8s.io/kubernetes/pkg/controller/endpointslice/topologycache"
|
||||||
endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
|
endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
|
||||||
endpointsliceutil "k8s.io/kubernetes/pkg/controller/util/endpointslice"
|
endpointsliceutil "k8s.io/kubernetes/pkg/controller/util/endpointslice"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
utilpointer "k8s.io/utils/pointer"
|
utilpointer "k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -418,12 +415,11 @@ func TestSyncService(t *testing.T) {
|
|||||||
deletionTimestamp := metav1.Now()
|
deletionTimestamp := metav1.Now()
|
||||||
|
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
name string
|
name string
|
||||||
service *v1.Service
|
service *v1.Service
|
||||||
pods []*v1.Pod
|
pods []*v1.Pod
|
||||||
expectedEndpointPorts []discovery.EndpointPort
|
expectedEndpointPorts []discovery.EndpointPort
|
||||||
expectedEndpoints []discovery.Endpoint
|
expectedEndpoints []discovery.Endpoint
|
||||||
terminatingGateEnabled bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pods with multiple IPs and Service with ipFamilies=ipv4",
|
name: "pods with multiple IPs and Service with ipFamilies=ipv4",
|
||||||
@ -522,7 +518,9 @@ func TestSyncService(t *testing.T) {
|
|||||||
expectedEndpoints: []discovery.Endpoint{
|
expectedEndpoints: []discovery.Endpoint{
|
||||||
{
|
{
|
||||||
Conditions: discovery.EndpointConditions{
|
Conditions: discovery.EndpointConditions{
|
||||||
Ready: utilpointer.BoolPtr(true),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
},
|
},
|
||||||
Addresses: []string{"10.0.0.1"},
|
Addresses: []string{"10.0.0.1"},
|
||||||
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: "default", Name: "pod0"},
|
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: "default", Name: "pod0"},
|
||||||
@ -530,7 +528,9 @@ func TestSyncService(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Conditions: discovery.EndpointConditions{
|
Conditions: discovery.EndpointConditions{
|
||||||
Ready: utilpointer.BoolPtr(true),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
},
|
},
|
||||||
Addresses: []string{"10.0.0.2"},
|
Addresses: []string{"10.0.0.2"},
|
||||||
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: "default", Name: "pod1"},
|
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: "default", Name: "pod1"},
|
||||||
@ -635,7 +635,9 @@ func TestSyncService(t *testing.T) {
|
|||||||
expectedEndpoints: []discovery.Endpoint{
|
expectedEndpoints: []discovery.Endpoint{
|
||||||
{
|
{
|
||||||
Conditions: discovery.EndpointConditions{
|
Conditions: discovery.EndpointConditions{
|
||||||
Ready: utilpointer.BoolPtr(true),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
},
|
},
|
||||||
Addresses: []string{"fd08::5678:0000:0000:9abc:def0"},
|
Addresses: []string{"fd08::5678:0000:0000:9abc:def0"},
|
||||||
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: "default", Name: "pod1"},
|
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: "default", Name: "pod1"},
|
||||||
@ -644,7 +646,7 @@ func TestSyncService(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Terminating pods with EndpointSliceTerminatingCondition enabled",
|
name: "Terminating pods",
|
||||||
service: &v1.Service{
|
service: &v1.Service{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "foobar",
|
Name: "foobar",
|
||||||
@ -757,114 +759,9 @@ func TestSyncService(t *testing.T) {
|
|||||||
NodeName: utilpointer.StringPtr("node-1"),
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
terminatingGateEnabled: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Terminating pods with EndpointSliceTerminatingCondition disabled",
|
name: "Not ready terminating pods",
|
||||||
service: &v1.Service{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "foobar",
|
|
||||||
Namespace: "default",
|
|
||||||
CreationTimestamp: creationTimestamp,
|
|
||||||
},
|
|
||||||
Spec: v1.ServiceSpec{
|
|
||||||
Ports: []v1.ServicePort{
|
|
||||||
{Name: "tcp-example", TargetPort: intstr.FromInt(80), Protocol: v1.ProtocolTCP},
|
|
||||||
{Name: "udp-example", TargetPort: intstr.FromInt(161), Protocol: v1.ProtocolUDP},
|
|
||||||
{Name: "sctp-example", TargetPort: intstr.FromInt(3456), Protocol: v1.ProtocolSCTP},
|
|
||||||
},
|
|
||||||
Selector: map[string]string{"foo": "bar"},
|
|
||||||
IPFamilies: []v1.IPFamily{v1.IPv4Protocol},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pods: []*v1.Pod{
|
|
||||||
{
|
|
||||||
// one ready pod for comparison
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Namespace: "default",
|
|
||||||
Name: "pod0",
|
|
||||||
Labels: map[string]string{"foo": "bar"},
|
|
||||||
DeletionTimestamp: nil,
|
|
||||||
},
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Containers: []v1.Container{{
|
|
||||||
Name: "container-1",
|
|
||||||
}},
|
|
||||||
NodeName: "node-1",
|
|
||||||
},
|
|
||||||
Status: v1.PodStatus{
|
|
||||||
PodIP: "10.0.0.1",
|
|
||||||
PodIPs: []v1.PodIP{{
|
|
||||||
IP: "10.0.0.1",
|
|
||||||
}},
|
|
||||||
Conditions: []v1.PodCondition{
|
|
||||||
{
|
|
||||||
Type: v1.PodReady,
|
|
||||||
Status: v1.ConditionTrue,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Namespace: "default",
|
|
||||||
Name: "pod1",
|
|
||||||
Labels: map[string]string{"foo": "bar"},
|
|
||||||
DeletionTimestamp: &deletionTimestamp,
|
|
||||||
},
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Containers: []v1.Container{{
|
|
||||||
Name: "container-1",
|
|
||||||
}},
|
|
||||||
NodeName: "node-1",
|
|
||||||
},
|
|
||||||
Status: v1.PodStatus{
|
|
||||||
PodIP: "10.0.0.2",
|
|
||||||
PodIPs: []v1.PodIP{
|
|
||||||
{
|
|
||||||
IP: "10.0.0.2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Conditions: []v1.PodCondition{
|
|
||||||
{
|
|
||||||
Type: v1.PodReady,
|
|
||||||
Status: v1.ConditionTrue,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEndpointPorts: []discovery.EndpointPort{
|
|
||||||
{
|
|
||||||
Name: utilpointer.StringPtr("sctp-example"),
|
|
||||||
Protocol: protoPtr(v1.ProtocolSCTP),
|
|
||||||
Port: utilpointer.Int32Ptr(int32(3456)),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: utilpointer.StringPtr("udp-example"),
|
|
||||||
Protocol: protoPtr(v1.ProtocolUDP),
|
|
||||||
Port: utilpointer.Int32Ptr(int32(161)),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: utilpointer.StringPtr("tcp-example"),
|
|
||||||
Protocol: protoPtr(v1.ProtocolTCP),
|
|
||||||
Port: utilpointer.Int32Ptr(int32(80)),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEndpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Ready: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
Addresses: []string{"10.0.0.1"},
|
|
||||||
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: "default", Name: "pod0"},
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
terminatingGateEnabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Not ready terminating pods with EndpointSliceTerminatingCondition enabled",
|
|
||||||
service: &v1.Service{
|
service: &v1.Service{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "foobar",
|
Name: "foobar",
|
||||||
@ -977,118 +874,11 @@ func TestSyncService(t *testing.T) {
|
|||||||
NodeName: utilpointer.StringPtr("node-1"),
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
terminatingGateEnabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Not ready terminating pods with EndpointSliceTerminatingCondition disabled",
|
|
||||||
service: &v1.Service{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "foobar",
|
|
||||||
Namespace: "default",
|
|
||||||
CreationTimestamp: creationTimestamp,
|
|
||||||
},
|
|
||||||
Spec: v1.ServiceSpec{
|
|
||||||
Ports: []v1.ServicePort{
|
|
||||||
{Name: "tcp-example", TargetPort: intstr.FromInt(80), Protocol: v1.ProtocolTCP},
|
|
||||||
{Name: "udp-example", TargetPort: intstr.FromInt(161), Protocol: v1.ProtocolUDP},
|
|
||||||
{Name: "sctp-example", TargetPort: intstr.FromInt(3456), Protocol: v1.ProtocolSCTP},
|
|
||||||
},
|
|
||||||
Selector: map[string]string{"foo": "bar"},
|
|
||||||
IPFamilies: []v1.IPFamily{v1.IPv4Protocol},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pods: []*v1.Pod{
|
|
||||||
{
|
|
||||||
// one ready pod for comparison
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Namespace: "default",
|
|
||||||
Name: "pod0",
|
|
||||||
Labels: map[string]string{"foo": "bar"},
|
|
||||||
DeletionTimestamp: nil,
|
|
||||||
},
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Containers: []v1.Container{{
|
|
||||||
Name: "container-1",
|
|
||||||
}},
|
|
||||||
NodeName: "node-1",
|
|
||||||
},
|
|
||||||
Status: v1.PodStatus{
|
|
||||||
PodIP: "10.0.0.1",
|
|
||||||
PodIPs: []v1.PodIP{{
|
|
||||||
IP: "10.0.0.1",
|
|
||||||
}},
|
|
||||||
Conditions: []v1.PodCondition{
|
|
||||||
{
|
|
||||||
Type: v1.PodReady,
|
|
||||||
Status: v1.ConditionTrue,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Namespace: "default",
|
|
||||||
Name: "pod1",
|
|
||||||
Labels: map[string]string{"foo": "bar"},
|
|
||||||
DeletionTimestamp: &deletionTimestamp,
|
|
||||||
},
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Containers: []v1.Container{{
|
|
||||||
Name: "container-1",
|
|
||||||
}},
|
|
||||||
NodeName: "node-1",
|
|
||||||
},
|
|
||||||
Status: v1.PodStatus{
|
|
||||||
PodIP: "10.0.0.2",
|
|
||||||
PodIPs: []v1.PodIP{
|
|
||||||
{
|
|
||||||
IP: "10.0.0.2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Conditions: []v1.PodCondition{
|
|
||||||
{
|
|
||||||
Type: v1.PodReady,
|
|
||||||
Status: v1.ConditionFalse,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEndpointPorts: []discovery.EndpointPort{
|
|
||||||
{
|
|
||||||
Name: utilpointer.StringPtr("sctp-example"),
|
|
||||||
Protocol: protoPtr(v1.ProtocolSCTP),
|
|
||||||
Port: utilpointer.Int32Ptr(int32(3456)),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: utilpointer.StringPtr("udp-example"),
|
|
||||||
Protocol: protoPtr(v1.ProtocolUDP),
|
|
||||||
Port: utilpointer.Int32Ptr(int32(161)),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: utilpointer.StringPtr("tcp-example"),
|
|
||||||
Protocol: protoPtr(v1.ProtocolTCP),
|
|
||||||
Port: utilpointer.Int32Ptr(int32(80)),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEndpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Ready: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
Addresses: []string{"10.0.0.1"},
|
|
||||||
TargetRef: &v1.ObjectReference{Kind: "Pod", Namespace: "default", Name: "pod0"},
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
terminatingGateEnabled: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range testcases {
|
for _, testcase := range testcases {
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testcase.terminatingGateEnabled)()
|
|
||||||
|
|
||||||
client, esController := newController([]string{"node-1"}, time.Duration(0))
|
client, esController := newController([]string{"node-1"}, time.Duration(0))
|
||||||
|
|
||||||
for _, pod := range testcase.pods {
|
for _, pod := range testcase.pods {
|
||||||
|
@ -30,7 +30,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
corelisters "k8s.io/client-go/listers/core/v1"
|
corelisters "k8s.io/client-go/listers/core/v1"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
@ -38,7 +37,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/controller/endpointslice/topologycache"
|
"k8s.io/kubernetes/pkg/controller/endpointslice/topologycache"
|
||||||
endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
|
endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
|
||||||
endpointsliceutil "k8s.io/kubernetes/pkg/controller/util/endpointslice"
|
endpointsliceutil "k8s.io/kubernetes/pkg/controller/util/endpointslice"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// reconciler is responsible for transforming current EndpointSlice state into
|
// reconciler is responsible for transforming current EndpointSlice state into
|
||||||
@ -154,8 +152,7 @@ func (r *reconciler) reconcileByAddressType(service *corev1.Service, pods []*cor
|
|||||||
desiredEndpointsByPortMap := map[endpointutil.PortMapKey]endpointsliceutil.EndpointSet{}
|
desiredEndpointsByPortMap := map[endpointutil.PortMapKey]endpointsliceutil.EndpointSet{}
|
||||||
|
|
||||||
for _, pod := range pods {
|
for _, pod := range pods {
|
||||||
includeTerminating := service.Spec.PublishNotReadyAddresses || utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceTerminatingCondition)
|
if !endpointutil.ShouldPodBeInEndpoints(pod, true) {
|
||||||
if !endpointutil.ShouldPodBeInEndpoints(pod, includeTerminating) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,18 +32,15 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
corelisters "k8s.io/client-go/listers/core/v1"
|
corelisters "k8s.io/client-go/listers/core/v1"
|
||||||
k8stesting "k8s.io/client-go/testing"
|
k8stesting "k8s.io/client-go/testing"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
|
||||||
"k8s.io/component-base/metrics/testutil"
|
"k8s.io/component-base/metrics/testutil"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/controller/endpointslice/metrics"
|
"k8s.io/kubernetes/pkg/controller/endpointslice/metrics"
|
||||||
"k8s.io/kubernetes/pkg/controller/endpointslice/topologycache"
|
"k8s.io/kubernetes/pkg/controller/endpointslice/topologycache"
|
||||||
endpointsliceutil "k8s.io/kubernetes/pkg/controller/util/endpointslice"
|
endpointsliceutil "k8s.io/kubernetes/pkg/controller/util/endpointslice"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
utilpointer "k8s.io/utils/pointer"
|
utilpointer "k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -119,17 +116,20 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
expectedEndpoint discovery.Endpoint
|
expectedEndpoint discovery.Endpoint
|
||||||
expectedLabels map[string]string
|
expectedLabels map[string]string
|
||||||
expectedEndpointPerSlice map[discovery.AddressType][]discovery.Endpoint
|
expectedEndpointPerSlice map[discovery.AddressType][]discovery.Endpoint
|
||||||
terminatingGateEnabled bool
|
|
||||||
}{
|
}{
|
||||||
"no-family-service": {
|
"no-family-service": {
|
||||||
service: noFamilyService,
|
service: noFamilyService,
|
||||||
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
||||||
discovery.AddressTypeIPv4: {
|
discovery.AddressTypeIPv4: {
|
||||||
{
|
{
|
||||||
Addresses: []string{"1.2.3.4"},
|
Addresses: []string{"1.2.3.4"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -144,29 +144,6 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"ipv4": {
|
"ipv4": {
|
||||||
service: svcv4,
|
|
||||||
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
|
||||||
discovery.AddressTypeIPv4: {
|
|
||||||
{
|
|
||||||
Addresses: []string{"1.2.3.4"},
|
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
TargetRef: &corev1.ObjectReference{
|
|
||||||
Kind: "Pod",
|
|
||||||
Namespace: namespace,
|
|
||||||
Name: "pod1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedLabels: map[string]string{
|
|
||||||
discovery.LabelManagedBy: controllerName,
|
|
||||||
discovery.LabelServiceName: "foo",
|
|
||||||
corev1.IsHeadlessService: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"ipv4-with-terminating-gate-enabled": {
|
|
||||||
service: svcv4,
|
service: svcv4,
|
||||||
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
||||||
discovery.AddressTypeIPv4: {
|
discovery.AddressTypeIPv4: {
|
||||||
@ -192,17 +169,20 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
discovery.LabelServiceName: "foo",
|
discovery.LabelServiceName: "foo",
|
||||||
corev1.IsHeadlessService: "",
|
corev1.IsHeadlessService: "",
|
||||||
},
|
},
|
||||||
terminatingGateEnabled: true,
|
|
||||||
},
|
},
|
||||||
"ipv4-clusterip": {
|
"ipv4-clusterip": {
|
||||||
service: svcv4ClusterIP,
|
service: svcv4ClusterIP,
|
||||||
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
||||||
discovery.AddressTypeIPv4: {
|
discovery.AddressTypeIPv4: {
|
||||||
{
|
{
|
||||||
Addresses: []string{"1.2.3.4"},
|
Addresses: []string{"1.2.3.4"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -213,10 +193,14 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedAddressType: discovery.AddressTypeIPv4,
|
expectedAddressType: discovery.AddressTypeIPv4,
|
||||||
expectedEndpoint: discovery.Endpoint{
|
expectedEndpoint: discovery.Endpoint{
|
||||||
Addresses: []string{"1.2.3.4"},
|
Addresses: []string{"1.2.3.4"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -233,10 +217,14 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
||||||
discovery.AddressTypeIPv4: {
|
discovery.AddressTypeIPv4: {
|
||||||
{
|
{
|
||||||
Addresses: []string{"1.2.3.4"},
|
Addresses: []string{"1.2.3.4"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -247,10 +235,14 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedAddressType: discovery.AddressTypeIPv4,
|
expectedAddressType: discovery.AddressTypeIPv4,
|
||||||
expectedEndpoint: discovery.Endpoint{
|
expectedEndpoint: discovery.Endpoint{
|
||||||
Addresses: []string{"1.2.3.4"},
|
Addresses: []string{"1.2.3.4"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -269,10 +261,14 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
||||||
discovery.AddressTypeIPv4: {
|
discovery.AddressTypeIPv4: {
|
||||||
{
|
{
|
||||||
Addresses: []string{"1.2.3.4"},
|
Addresses: []string{"1.2.3.4"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -283,10 +279,14 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedAddressType: discovery.AddressTypeIPv4,
|
expectedAddressType: discovery.AddressTypeIPv4,
|
||||||
expectedEndpoint: discovery.Endpoint{
|
expectedEndpoint: discovery.Endpoint{
|
||||||
Addresses: []string{"1.2.3.4"},
|
Addresses: []string{"1.2.3.4"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -305,10 +305,14 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
||||||
discovery.AddressTypeIPv6: {
|
discovery.AddressTypeIPv6: {
|
||||||
{
|
{
|
||||||
Addresses: []string{"1234::5678:0000:0000:9abc:def0"},
|
Addresses: []string{"1234::5678:0000:0000:9abc:def0"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -329,10 +333,14 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
||||||
discovery.AddressTypeIPv6: {
|
discovery.AddressTypeIPv6: {
|
||||||
{
|
{
|
||||||
Addresses: []string{"1234::5678:0000:0000:9abc:def0"},
|
Addresses: []string{"1234::5678:0000:0000:9abc:def0"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -352,10 +360,14 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
expectedEndpointPerSlice: map[discovery.AddressType][]discovery.Endpoint{
|
||||||
discovery.AddressTypeIPv6: {
|
discovery.AddressTypeIPv6: {
|
||||||
{
|
{
|
||||||
Addresses: []string{"1234::5678:0000:0000:9abc:def0"},
|
Addresses: []string{"1234::5678:0000:0000:9abc:def0"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -365,10 +377,14 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
discovery.AddressTypeIPv4: {
|
discovery.AddressTypeIPv4: {
|
||||||
{
|
{
|
||||||
Addresses: []string{"1.2.3.4"},
|
Addresses: []string{"1.2.3.4"},
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
Conditions: discovery.EndpointConditions{
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &corev1.ObjectReference{
|
TargetRef: &corev1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
@ -386,8 +402,6 @@ func TestReconcile1Pod(t *testing.T) {
|
|||||||
|
|
||||||
for name, testCase := range testCases {
|
for name, testCase := range testCases {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testCase.terminatingGateEnabled)()
|
|
||||||
|
|
||||||
client := newClientset()
|
client := newClientset()
|
||||||
setupMetrics()
|
setupMetrics()
|
||||||
triggerTime := time.Now().UTC()
|
triggerTime := time.Now().UTC()
|
||||||
|
@ -20,14 +20,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
discovery "k8s.io/api/discovery/v1"
|
discovery "k8s.io/api/discovery/v1"
|
||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||||
@ -35,7 +34,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||||
"k8s.io/kubernetes/pkg/apis/discovery/validation"
|
"k8s.io/kubernetes/pkg/apis/discovery/validation"
|
||||||
endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
|
endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
utilnet "k8s.io/utils/net"
|
utilnet "k8s.io/utils/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,7 +47,9 @@ func podToEndpoint(pod *v1.Pod, node *v1.Node, service *v1.Service, addressType
|
|||||||
ep := discovery.Endpoint{
|
ep := discovery.Endpoint{
|
||||||
Addresses: getEndpointAddresses(pod.Status, service, addressType),
|
Addresses: getEndpointAddresses(pod.Status, service, addressType),
|
||||||
Conditions: discovery.EndpointConditions{
|
Conditions: discovery.EndpointConditions{
|
||||||
Ready: &ready,
|
Ready: &ready,
|
||||||
|
Serving: &serving,
|
||||||
|
Terminating: &terminating,
|
||||||
},
|
},
|
||||||
TargetRef: &v1.ObjectReference{
|
TargetRef: &v1.ObjectReference{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
@ -59,11 +59,6 @@ func podToEndpoint(pod *v1.Pod, node *v1.Node, service *v1.Service, addressType
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceTerminatingCondition) {
|
|
||||||
ep.Conditions.Serving = &serving
|
|
||||||
ep.Conditions.Terminating = &terminating
|
|
||||||
}
|
|
||||||
|
|
||||||
if pod.Spec.NodeName != "" {
|
if pod.Spec.NodeName != "" {
|
||||||
ep.NodeName = &pod.Spec.NodeName
|
ep.NodeName = &pod.Spec.NodeName
|
||||||
}
|
}
|
||||||
|
@ -31,11 +31,8 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/apimachinery/pkg/util/rand"
|
"k8s.io/apimachinery/pkg/util/rand"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
k8stesting "k8s.io/client-go/testing"
|
k8stesting "k8s.io/client-go/testing"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
utilpointer "k8s.io/utils/pointer"
|
utilpointer "k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -251,131 +248,11 @@ func TestPodToEndpoint(t *testing.T) {
|
|||||||
svc *v1.Service
|
svc *v1.Service
|
||||||
expectedEndpoint discovery.Endpoint
|
expectedEndpoint discovery.Endpoint
|
||||||
publishNotReadyAddresses bool
|
publishNotReadyAddresses bool
|
||||||
terminatingGateEnabled bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Ready pod",
|
name: "Ready pod",
|
||||||
pod: readyPod,
|
pod: readyPod,
|
||||||
svc: &svc,
|
svc: &svc,
|
||||||
expectedEndpoint: discovery.Endpoint{
|
|
||||||
Addresses: []string{"1.2.3.5"},
|
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
TargetRef: &v1.ObjectReference{
|
|
||||||
Kind: "Pod",
|
|
||||||
Namespace: ns,
|
|
||||||
Name: readyPod.Name,
|
|
||||||
UID: readyPod.UID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Ready pod + publishNotReadyAddresses",
|
|
||||||
pod: readyPod,
|
|
||||||
svc: &svcPublishNotReady,
|
|
||||||
expectedEndpoint: discovery.Endpoint{
|
|
||||||
Addresses: []string{"1.2.3.5"},
|
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
TargetRef: &v1.ObjectReference{
|
|
||||||
Kind: "Pod",
|
|
||||||
Namespace: ns,
|
|
||||||
Name: readyPod.Name,
|
|
||||||
UID: readyPod.UID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Unready pod",
|
|
||||||
pod: unreadyPod,
|
|
||||||
svc: &svc,
|
|
||||||
expectedEndpoint: discovery.Endpoint{
|
|
||||||
Addresses: []string{"1.2.3.5"},
|
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(false)},
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
TargetRef: &v1.ObjectReference{
|
|
||||||
Kind: "Pod",
|
|
||||||
Namespace: ns,
|
|
||||||
Name: readyPod.Name,
|
|
||||||
UID: readyPod.UID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Unready pod + publishNotReadyAddresses",
|
|
||||||
pod: unreadyPod,
|
|
||||||
svc: &svcPublishNotReady,
|
|
||||||
expectedEndpoint: discovery.Endpoint{
|
|
||||||
Addresses: []string{"1.2.3.5"},
|
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
TargetRef: &v1.ObjectReference{
|
|
||||||
Kind: "Pod",
|
|
||||||
Namespace: ns,
|
|
||||||
Name: readyPod.Name,
|
|
||||||
UID: readyPod.UID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Ready pod + node labels",
|
|
||||||
pod: readyPod,
|
|
||||||
node: node1,
|
|
||||||
svc: &svc,
|
|
||||||
expectedEndpoint: discovery.Endpoint{
|
|
||||||
Addresses: []string{"1.2.3.5"},
|
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
TargetRef: &v1.ObjectReference{
|
|
||||||
Kind: "Pod",
|
|
||||||
Namespace: ns,
|
|
||||||
Name: readyPod.Name,
|
|
||||||
UID: readyPod.UID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Multi IP Ready pod + node labels",
|
|
||||||
pod: multiIPPod,
|
|
||||||
node: node1,
|
|
||||||
svc: &svc,
|
|
||||||
expectedEndpoint: discovery.Endpoint{
|
|
||||||
Addresses: []string{"1.2.3.4"},
|
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
TargetRef: &v1.ObjectReference{
|
|
||||||
Kind: "Pod",
|
|
||||||
Namespace: ns,
|
|
||||||
Name: readyPod.Name,
|
|
||||||
UID: readyPod.UID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Ready pod + hostname",
|
|
||||||
pod: readyPodHostname,
|
|
||||||
node: node1,
|
|
||||||
svc: &svc,
|
|
||||||
expectedEndpoint: discovery.Endpoint{
|
|
||||||
Addresses: []string{"1.2.3.5"},
|
|
||||||
Conditions: discovery.EndpointConditions{Ready: utilpointer.BoolPtr(true)},
|
|
||||||
Hostname: &readyPodHostname.Spec.Hostname,
|
|
||||||
Zone: utilpointer.StringPtr("us-central1-a"),
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
TargetRef: &v1.ObjectReference{
|
|
||||||
Kind: "Pod",
|
|
||||||
Namespace: ns,
|
|
||||||
Name: readyPodHostname.Name,
|
|
||||||
UID: readyPodHostname.UID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Ready pod, terminating gate enabled",
|
|
||||||
pod: readyPod,
|
|
||||||
svc: &svc,
|
|
||||||
expectedEndpoint: discovery.Endpoint{
|
expectedEndpoint: discovery.Endpoint{
|
||||||
Addresses: []string{"1.2.3.5"},
|
Addresses: []string{"1.2.3.5"},
|
||||||
Conditions: discovery.EndpointConditions{
|
Conditions: discovery.EndpointConditions{
|
||||||
@ -391,16 +268,17 @@ func TestPodToEndpoint(t *testing.T) {
|
|||||||
UID: readyPod.UID,
|
UID: readyPod.UID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
terminatingGateEnabled: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Ready terminating pod, terminating gate disabled",
|
name: "Ready pod + publishNotReadyAddresses",
|
||||||
pod: readyTerminatingPod,
|
pod: readyPod,
|
||||||
svc: &svc,
|
svc: &svcPublishNotReady,
|
||||||
expectedEndpoint: discovery.Endpoint{
|
expectedEndpoint: discovery.Endpoint{
|
||||||
Addresses: []string{"1.2.3.5"},
|
Addresses: []string{"1.2.3.5"},
|
||||||
Conditions: discovery.EndpointConditions{
|
Conditions: discovery.EndpointConditions{
|
||||||
Ready: utilpointer.BoolPtr(false),
|
Ready: utilpointer.BoolPtr(true),
|
||||||
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
},
|
},
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
TargetRef: &v1.ObjectReference{
|
TargetRef: &v1.ObjectReference{
|
||||||
@ -410,10 +288,136 @@ func TestPodToEndpoint(t *testing.T) {
|
|||||||
UID: readyPod.UID,
|
UID: readyPod.UID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
terminatingGateEnabled: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Ready terminating pod, terminating gate enabled",
|
name: "Unready pod",
|
||||||
|
pod: unreadyPod,
|
||||||
|
svc: &svc,
|
||||||
|
expectedEndpoint: discovery.Endpoint{
|
||||||
|
Addresses: []string{"1.2.3.5"},
|
||||||
|
Conditions: discovery.EndpointConditions{
|
||||||
|
Ready: utilpointer.BoolPtr(false),
|
||||||
|
Serving: utilpointer.BoolPtr(false),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
|
TargetRef: &v1.ObjectReference{
|
||||||
|
Kind: "Pod",
|
||||||
|
Namespace: ns,
|
||||||
|
Name: readyPod.Name,
|
||||||
|
UID: readyPod.UID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unready pod + publishNotReadyAddresses",
|
||||||
|
pod: unreadyPod,
|
||||||
|
svc: &svcPublishNotReady,
|
||||||
|
expectedEndpoint: discovery.Endpoint{
|
||||||
|
Addresses: []string{"1.2.3.5"},
|
||||||
|
Conditions: discovery.EndpointConditions{
|
||||||
|
Ready: utilpointer.BoolPtr(true),
|
||||||
|
Serving: utilpointer.BoolPtr(false),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
|
TargetRef: &v1.ObjectReference{
|
||||||
|
Kind: "Pod",
|
||||||
|
Namespace: ns,
|
||||||
|
Name: readyPod.Name,
|
||||||
|
UID: readyPod.UID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ready pod + node labels",
|
||||||
|
pod: readyPod,
|
||||||
|
node: node1,
|
||||||
|
svc: &svc,
|
||||||
|
expectedEndpoint: discovery.Endpoint{
|
||||||
|
Addresses: []string{"1.2.3.5"},
|
||||||
|
Conditions: discovery.EndpointConditions{
|
||||||
|
Ready: utilpointer.BoolPtr(true),
|
||||||
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
|
TargetRef: &v1.ObjectReference{
|
||||||
|
Kind: "Pod",
|
||||||
|
Namespace: ns,
|
||||||
|
Name: readyPod.Name,
|
||||||
|
UID: readyPod.UID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multi IP Ready pod + node labels",
|
||||||
|
pod: multiIPPod,
|
||||||
|
node: node1,
|
||||||
|
svc: &svc,
|
||||||
|
expectedEndpoint: discovery.Endpoint{
|
||||||
|
Addresses: []string{"1.2.3.4"},
|
||||||
|
Conditions: discovery.EndpointConditions{
|
||||||
|
Ready: utilpointer.BoolPtr(true),
|
||||||
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
|
TargetRef: &v1.ObjectReference{
|
||||||
|
Kind: "Pod",
|
||||||
|
Namespace: ns,
|
||||||
|
Name: readyPod.Name,
|
||||||
|
UID: readyPod.UID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ready pod + hostname",
|
||||||
|
pod: readyPodHostname,
|
||||||
|
node: node1,
|
||||||
|
svc: &svc,
|
||||||
|
expectedEndpoint: discovery.Endpoint{
|
||||||
|
Addresses: []string{"1.2.3.5"},
|
||||||
|
Conditions: discovery.EndpointConditions{
|
||||||
|
Ready: utilpointer.BoolPtr(true),
|
||||||
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
Hostname: &readyPodHostname.Spec.Hostname,
|
||||||
|
Zone: utilpointer.StringPtr("us-central1-a"),
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
|
TargetRef: &v1.ObjectReference{
|
||||||
|
Kind: "Pod",
|
||||||
|
Namespace: ns,
|
||||||
|
Name: readyPodHostname.Name,
|
||||||
|
UID: readyPodHostname.UID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ready pod",
|
||||||
|
pod: readyPod,
|
||||||
|
svc: &svc,
|
||||||
|
expectedEndpoint: discovery.Endpoint{
|
||||||
|
Addresses: []string{"1.2.3.5"},
|
||||||
|
Conditions: discovery.EndpointConditions{
|
||||||
|
Ready: utilpointer.BoolPtr(true),
|
||||||
|
Serving: utilpointer.BoolPtr(true),
|
||||||
|
Terminating: utilpointer.BoolPtr(false),
|
||||||
|
},
|
||||||
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
|
TargetRef: &v1.ObjectReference{
|
||||||
|
Kind: "Pod",
|
||||||
|
Namespace: ns,
|
||||||
|
Name: readyPod.Name,
|
||||||
|
UID: readyPod.UID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ready terminating pod",
|
||||||
pod: readyTerminatingPod,
|
pod: readyTerminatingPod,
|
||||||
svc: &svc,
|
svc: &svc,
|
||||||
expectedEndpoint: discovery.Endpoint{
|
expectedEndpoint: discovery.Endpoint{
|
||||||
@ -431,29 +435,9 @@ func TestPodToEndpoint(t *testing.T) {
|
|||||||
UID: readyPod.UID,
|
UID: readyPod.UID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
terminatingGateEnabled: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Not ready terminating pod, terminating gate disabled",
|
name: "Not ready terminating pod",
|
||||||
pod: unreadyTerminatingPod,
|
|
||||||
svc: &svc,
|
|
||||||
expectedEndpoint: discovery.Endpoint{
|
|
||||||
Addresses: []string{"1.2.3.5"},
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Ready: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
|
||||||
TargetRef: &v1.ObjectReference{
|
|
||||||
Kind: "Pod",
|
|
||||||
Namespace: ns,
|
|
||||||
Name: readyPod.Name,
|
|
||||||
UID: readyPod.UID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
terminatingGateEnabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Not ready terminating pod, terminating gate enabled",
|
|
||||||
pod: unreadyTerminatingPod,
|
pod: unreadyTerminatingPod,
|
||||||
svc: &svc,
|
svc: &svc,
|
||||||
expectedEndpoint: discovery.Endpoint{
|
expectedEndpoint: discovery.Endpoint{
|
||||||
@ -471,14 +455,11 @@ func TestPodToEndpoint(t *testing.T) {
|
|||||||
UID: readyPod.UID,
|
UID: readyPod.UID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
terminatingGateEnabled: true,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testCase.terminatingGateEnabled)()
|
|
||||||
|
|
||||||
endpoint := podToEndpoint(testCase.pod, testCase.node, testCase.svc, discovery.AddressTypeIPv4)
|
endpoint := podToEndpoint(testCase.pod, testCase.node, testCase.svc, discovery.AddressTypeIPv4)
|
||||||
if !reflect.DeepEqual(testCase.expectedEndpoint, endpoint) {
|
if !reflect.DeepEqual(testCase.expectedEndpoint, endpoint) {
|
||||||
t.Errorf("Expected endpoint: %+v, got: %+v", testCase.expectedEndpoint, endpoint)
|
t.Errorf("Expected endpoint: %+v, got: %+v", testCase.expectedEndpoint, endpoint)
|
||||||
|
@ -306,16 +306,11 @@ func EndpointsEqualBeyondHash(ep1, ep2 *discovery.Endpoint) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serving and Terminating will only be set when the EndpointSliceTerminatingCondition feature is on.
|
if boolPtrChanged(ep1.Conditions.Serving, ep2.Conditions.Serving) {
|
||||||
// Ignore their difference if the expected or actual value is nil, which means the feature enablement is changed.
|
|
||||||
// Otherwise all EndpointSlices in the system would be updated on the first controller-manager restart even without
|
|
||||||
// actual changes, leading to delay in processing legitimate updates.
|
|
||||||
// Its value will be set to the expected one when there is an actual change triggering update of this EndpointSlice.
|
|
||||||
if ep1.Conditions.Serving != nil && ep2.Conditions.Serving != nil && *ep1.Conditions.Serving != *ep2.Conditions.Serving {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if ep1.Conditions.Terminating != nil && ep2.Conditions.Terminating != nil && *ep1.Conditions.Terminating != *ep2.Conditions.Terminating {
|
if boolPtrChanged(ep1.Conditions.Terminating, ep2.Conditions.Terminating) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -776,7 +776,7 @@ func TestEndpointsEqualBeyondHash(t *testing.T) {
|
|||||||
Zone: utilpointer.StringPtr("zone-1"),
|
Zone: utilpointer.StringPtr("zone-1"),
|
||||||
NodeName: utilpointer.StringPtr("node-1"),
|
NodeName: utilpointer.StringPtr("node-1"),
|
||||||
},
|
},
|
||||||
expected: true,
|
expected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Serving condition changed from false to true",
|
name: "Serving condition changed from false to true",
|
||||||
|
@ -269,6 +269,7 @@ const (
|
|||||||
// kep: https://kep.k8s.io/1672
|
// kep: https://kep.k8s.io/1672
|
||||||
// alpha: v1.20
|
// alpha: v1.20
|
||||||
// beta: v1.22
|
// beta: v1.22
|
||||||
|
// GA: v1.26
|
||||||
//
|
//
|
||||||
// Enable Terminating condition in Endpoint Slices.
|
// Enable Terminating condition in Endpoint Slices.
|
||||||
EndpointSliceTerminatingCondition featuregate.Feature = "EndpointSliceTerminatingCondition"
|
EndpointSliceTerminatingCondition featuregate.Feature = "EndpointSliceTerminatingCondition"
|
||||||
@ -899,7 +900,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
|
|
||||||
DownwardAPIHugePages: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.22
|
DownwardAPIHugePages: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.22
|
||||||
|
|
||||||
EndpointSliceTerminatingCondition: {Default: true, PreRelease: featuregate.Beta},
|
EndpointSliceTerminatingCondition: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in v1.28
|
||||||
|
|
||||||
EphemeralContainers: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27
|
EphemeralContainers: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.27
|
||||||
|
|
||||||
|
8
pkg/generated/openapi/zz_generated.openapi.go
generated
8
pkg/generated/openapi/zz_generated.openapi.go
generated
@ -27012,14 +27012,14 @@ func schema_k8sio_api_discovery_v1_EndpointConditions(ref common.ReferenceCallba
|
|||||||
},
|
},
|
||||||
"serving": {
|
"serving": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
Description: "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition.",
|
||||||
Type: []string{"boolean"},
|
Type: []string{"boolean"},
|
||||||
Format: "",
|
Format: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"terminating": {
|
"terminating": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
Description: "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating.",
|
||||||
Type: []string{"boolean"},
|
Type: []string{"boolean"},
|
||||||
Format: "",
|
Format: "",
|
||||||
},
|
},
|
||||||
@ -27367,14 +27367,14 @@ func schema_k8sio_api_discovery_v1beta1_EndpointConditions(ref common.ReferenceC
|
|||||||
},
|
},
|
||||||
"serving": {
|
"serving": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
Description: "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition.",
|
||||||
Type: []string{"boolean"},
|
Type: []string{"boolean"},
|
||||||
Format: "",
|
Format: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"terminating": {
|
"terminating": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
Description: "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating.",
|
||||||
Type: []string{"boolean"},
|
Type: []string{"boolean"},
|
||||||
Format: "",
|
Format: "",
|
||||||
},
|
},
|
||||||
|
@ -123,15 +123,10 @@ func (endpointSliceStrategy) AllowUnconditionalUpdate() bool {
|
|||||||
|
|
||||||
// dropDisabledConditionsOnCreate will drop any fields that are disabled.
|
// dropDisabledConditionsOnCreate will drop any fields that are disabled.
|
||||||
func dropDisabledFieldsOnCreate(endpointSlice *discovery.EndpointSlice) {
|
func dropDisabledFieldsOnCreate(endpointSlice *discovery.EndpointSlice) {
|
||||||
dropTerminating := !utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceTerminatingCondition)
|
|
||||||
dropHints := !utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints)
|
dropHints := !utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints)
|
||||||
|
|
||||||
if dropHints || dropTerminating {
|
if dropHints {
|
||||||
for i := range endpointSlice.Endpoints {
|
for i := range endpointSlice.Endpoints {
|
||||||
if dropTerminating {
|
|
||||||
endpointSlice.Endpoints[i].Conditions.Serving = nil
|
|
||||||
endpointSlice.Endpoints[i].Conditions.Terminating = nil
|
|
||||||
}
|
|
||||||
if dropHints {
|
if dropHints {
|
||||||
endpointSlice.Endpoints[i].Hints = nil
|
endpointSlice.Endpoints[i].Hints = nil
|
||||||
}
|
}
|
||||||
@ -142,16 +137,6 @@ func dropDisabledFieldsOnCreate(endpointSlice *discovery.EndpointSlice) {
|
|||||||
// dropDisabledFieldsOnUpdate will drop any disable fields that have not already
|
// dropDisabledFieldsOnUpdate will drop any disable fields that have not already
|
||||||
// been set on the EndpointSlice.
|
// been set on the EndpointSlice.
|
||||||
func dropDisabledFieldsOnUpdate(oldEPS, newEPS *discovery.EndpointSlice) {
|
func dropDisabledFieldsOnUpdate(oldEPS, newEPS *discovery.EndpointSlice) {
|
||||||
dropTerminating := !utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceTerminatingCondition)
|
|
||||||
if dropTerminating {
|
|
||||||
for _, ep := range oldEPS.Endpoints {
|
|
||||||
if ep.Conditions.Serving != nil || ep.Conditions.Terminating != nil {
|
|
||||||
dropTerminating = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dropHints := !utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints)
|
dropHints := !utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints)
|
||||||
if dropHints {
|
if dropHints {
|
||||||
for _, ep := range oldEPS.Endpoints {
|
for _, ep := range oldEPS.Endpoints {
|
||||||
@ -162,12 +147,8 @@ func dropDisabledFieldsOnUpdate(oldEPS, newEPS *discovery.EndpointSlice) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dropHints || dropTerminating {
|
if dropHints {
|
||||||
for i := range newEPS.Endpoints {
|
for i := range newEPS.Endpoints {
|
||||||
if dropTerminating {
|
|
||||||
newEPS.Endpoints[i].Conditions.Serving = nil
|
|
||||||
newEPS.Endpoints[i].Conditions.Terminating = nil
|
|
||||||
}
|
|
||||||
if dropHints {
|
if dropHints {
|
||||||
newEPS.Endpoints[i].Hints = nil
|
newEPS.Endpoints[i].Hints = nil
|
||||||
}
|
}
|
||||||
|
@ -34,108 +34,11 @@ import (
|
|||||||
|
|
||||||
func Test_dropDisabledFieldsOnCreate(t *testing.T) {
|
func Test_dropDisabledFieldsOnCreate(t *testing.T) {
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
name string
|
name string
|
||||||
terminatingGateEnabled bool
|
hintsGateEnabled bool
|
||||||
hintsGateEnabled bool
|
eps *discovery.EndpointSlice
|
||||||
eps *discovery.EndpointSlice
|
expectedEPS *discovery.EndpointSlice
|
||||||
expectedEPS *discovery.EndpointSlice
|
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "terminating gate enabled, field should be allowed",
|
|
||||||
terminatingGateEnabled: true,
|
|
||||||
eps: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "terminating gate disabled, field should be set to nil",
|
|
||||||
terminatingGateEnabled: false,
|
|
||||||
eps: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "node name gate enabled, field should be allowed",
|
name: "node name gate enabled, field should be allowed",
|
||||||
eps: &discovery.EndpointSlice{
|
eps: &discovery.EndpointSlice{
|
||||||
@ -163,7 +66,6 @@ func Test_dropDisabledFieldsOnCreate(t *testing.T) {
|
|||||||
|
|
||||||
for _, testcase := range testcases {
|
for _, testcase := range testcases {
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testcase.terminatingGateEnabled)()
|
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, testcase.hintsGateEnabled)()
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, testcase.hintsGateEnabled)()
|
||||||
|
|
||||||
dropDisabledFieldsOnCreate(testcase.eps)
|
dropDisabledFieldsOnCreate(testcase.eps)
|
||||||
@ -178,290 +80,12 @@ func Test_dropDisabledFieldsOnCreate(t *testing.T) {
|
|||||||
|
|
||||||
func Test_dropDisabledFieldsOnUpdate(t *testing.T) {
|
func Test_dropDisabledFieldsOnUpdate(t *testing.T) {
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
name string
|
name string
|
||||||
terminatingGateEnabled bool
|
hintsGateEnabled bool
|
||||||
hintsGateEnabled bool
|
oldEPS *discovery.EndpointSlice
|
||||||
oldEPS *discovery.EndpointSlice
|
newEPS *discovery.EndpointSlice
|
||||||
newEPS *discovery.EndpointSlice
|
expectedEPS *discovery.EndpointSlice
|
||||||
expectedEPS *discovery.EndpointSlice
|
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "terminating gate enabled, field should be allowed",
|
|
||||||
terminatingGateEnabled: true,
|
|
||||||
oldEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
newEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "terminating gate disabled, and not set on existing EPS",
|
|
||||||
terminatingGateEnabled: false,
|
|
||||||
oldEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
newEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "terminating gate disabled, and set on existing EPS",
|
|
||||||
terminatingGateEnabled: false,
|
|
||||||
oldEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
newEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: nil,
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "terminating gate disabled, and set on existing EPS with new values",
|
|
||||||
terminatingGateEnabled: false,
|
|
||||||
oldEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(false),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Terminating: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
newEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(false),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEPS: &discovery.EndpointSlice{
|
|
||||||
Endpoints: []discovery.Endpoint{
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(true),
|
|
||||||
Terminating: utilpointer.BoolPtr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Serving: utilpointer.BoolPtr(false),
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Conditions: discovery.EndpointConditions{
|
|
||||||
Terminating: utilpointer.BoolPtr(false),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "node name gate enabled, set on new EPS",
|
name: "node name gate enabled, set on new EPS",
|
||||||
oldEPS: &discovery.EndpointSlice{
|
oldEPS: &discovery.EndpointSlice{
|
||||||
@ -658,7 +282,6 @@ func Test_dropDisabledFieldsOnUpdate(t *testing.T) {
|
|||||||
|
|
||||||
for _, testcase := range testcases {
|
for _, testcase := range testcases {
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testcase.terminatingGateEnabled)()
|
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, testcase.hintsGateEnabled)()
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, testcase.hintsGateEnabled)()
|
||||||
|
|
||||||
dropDisabledFieldsOnUpdate(testcase.oldEPS, testcase.newEPS)
|
dropDisabledFieldsOnUpdate(testcase.oldEPS, testcase.newEPS)
|
||||||
|
@ -93,15 +93,13 @@ message EndpointConditions {
|
|||||||
// serving is identical to ready except that it is set regardless of the
|
// serving is identical to ready except that it is set regardless of the
|
||||||
// terminating state of endpoints. This condition should be set to true for
|
// terminating state of endpoints. This condition should be set to true for
|
||||||
// a ready endpoint that is terminating. If nil, consumers should defer to
|
// a ready endpoint that is terminating. If nil, consumers should defer to
|
||||||
// the ready condition. This field can be enabled with the
|
// the ready condition.
|
||||||
// EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
optional bool serving = 2;
|
optional bool serving = 2;
|
||||||
|
|
||||||
// terminating indicates that this endpoint is terminating. A nil value
|
// terminating indicates that this endpoint is terminating. A nil value
|
||||||
// indicates an unknown state. Consumers should interpret this unknown state
|
// indicates an unknown state. Consumers should interpret this unknown state
|
||||||
// to mean that the endpoint is not terminating. This field can be enabled
|
// to mean that the endpoint is not terminating.
|
||||||
// with the EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
optional bool terminating = 3;
|
optional bool terminating = 3;
|
||||||
}
|
}
|
||||||
|
@ -126,15 +126,13 @@ type EndpointConditions struct {
|
|||||||
// serving is identical to ready except that it is set regardless of the
|
// serving is identical to ready except that it is set regardless of the
|
||||||
// terminating state of endpoints. This condition should be set to true for
|
// terminating state of endpoints. This condition should be set to true for
|
||||||
// a ready endpoint that is terminating. If nil, consumers should defer to
|
// a ready endpoint that is terminating. If nil, consumers should defer to
|
||||||
// the ready condition. This field can be enabled with the
|
// the ready condition.
|
||||||
// EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Serving *bool `json:"serving,omitempty" protobuf:"bytes,2,name=serving"`
|
Serving *bool `json:"serving,omitempty" protobuf:"bytes,2,name=serving"`
|
||||||
|
|
||||||
// terminating indicates that this endpoint is terminating. A nil value
|
// terminating indicates that this endpoint is terminating. A nil value
|
||||||
// indicates an unknown state. Consumers should interpret this unknown state
|
// indicates an unknown state. Consumers should interpret this unknown state
|
||||||
// to mean that the endpoint is not terminating. This field can be enabled
|
// to mean that the endpoint is not terminating.
|
||||||
// with the EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Terminating *bool `json:"terminating,omitempty" protobuf:"bytes,3,name=terminating"`
|
Terminating *bool `json:"terminating,omitempty" protobuf:"bytes,3,name=terminating"`
|
||||||
}
|
}
|
||||||
|
@ -46,8 +46,8 @@ func (Endpoint) SwaggerDoc() map[string]string {
|
|||||||
var map_EndpointConditions = map[string]string{
|
var map_EndpointConditions = map[string]string{
|
||||||
"": "EndpointConditions represents the current condition of an endpoint.",
|
"": "EndpointConditions represents the current condition of an endpoint.",
|
||||||
"ready": "ready indicates that this endpoint is prepared to receive traffic, according to whatever system is managing the endpoint. A nil value indicates an unknown state. In most cases consumers should interpret this unknown state as ready. For compatibility reasons, ready should never be \"true\" for terminating endpoints.",
|
"ready": "ready indicates that this endpoint is prepared to receive traffic, according to whatever system is managing the endpoint. A nil value indicates an unknown state. In most cases consumers should interpret this unknown state as ready. For compatibility reasons, ready should never be \"true\" for terminating endpoints.",
|
||||||
"serving": "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
"serving": "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition.",
|
||||||
"terminating": "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
"terminating": "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating.",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (EndpointConditions) SwaggerDoc() map[string]string {
|
func (EndpointConditions) SwaggerDoc() map[string]string {
|
||||||
|
@ -97,15 +97,13 @@ message EndpointConditions {
|
|||||||
// serving is identical to ready except that it is set regardless of the
|
// serving is identical to ready except that it is set regardless of the
|
||||||
// terminating state of endpoints. This condition should be set to true for
|
// terminating state of endpoints. This condition should be set to true for
|
||||||
// a ready endpoint that is terminating. If nil, consumers should defer to
|
// a ready endpoint that is terminating. If nil, consumers should defer to
|
||||||
// the ready condition. This field can be enabled with the
|
// the ready condition.
|
||||||
// EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
optional bool serving = 2;
|
optional bool serving = 2;
|
||||||
|
|
||||||
// terminating indicates that this endpoint is terminating. A nil value
|
// terminating indicates that this endpoint is terminating. A nil value
|
||||||
// indicates an unknown state. Consumers should interpret this unknown state
|
// indicates an unknown state. Consumers should interpret this unknown state
|
||||||
// to mean that the endpoint is not terminating. This field can be enabled
|
// to mean that the endpoint is not terminating.
|
||||||
// with the EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
optional bool terminating = 3;
|
optional bool terminating = 3;
|
||||||
}
|
}
|
||||||
|
@ -132,15 +132,13 @@ type EndpointConditions struct {
|
|||||||
// serving is identical to ready except that it is set regardless of the
|
// serving is identical to ready except that it is set regardless of the
|
||||||
// terminating state of endpoints. This condition should be set to true for
|
// terminating state of endpoints. This condition should be set to true for
|
||||||
// a ready endpoint that is terminating. If nil, consumers should defer to
|
// a ready endpoint that is terminating. If nil, consumers should defer to
|
||||||
// the ready condition. This field can be enabled with the
|
// the ready condition.
|
||||||
// EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Serving *bool `json:"serving,omitempty" protobuf:"bytes,2,name=serving"`
|
Serving *bool `json:"serving,omitempty" protobuf:"bytes,2,name=serving"`
|
||||||
|
|
||||||
// terminating indicates that this endpoint is terminating. A nil value
|
// terminating indicates that this endpoint is terminating. A nil value
|
||||||
// indicates an unknown state. Consumers should interpret this unknown state
|
// indicates an unknown state. Consumers should interpret this unknown state
|
||||||
// to mean that the endpoint is not terminating. This field can be enabled
|
// to mean that the endpoint is not terminating.
|
||||||
// with the EndpointSliceTerminatingCondition feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
Terminating *bool `json:"terminating,omitempty" protobuf:"bytes,3,name=terminating"`
|
Terminating *bool `json:"terminating,omitempty" protobuf:"bytes,3,name=terminating"`
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,8 @@ func (Endpoint) SwaggerDoc() map[string]string {
|
|||||||
var map_EndpointConditions = map[string]string{
|
var map_EndpointConditions = map[string]string{
|
||||||
"": "EndpointConditions represents the current condition of an endpoint.",
|
"": "EndpointConditions represents the current condition of an endpoint.",
|
||||||
"ready": "ready indicates that this endpoint is prepared to receive traffic, according to whatever system is managing the endpoint. A nil value indicates an unknown state. In most cases consumers should interpret this unknown state as ready. For compatibility reasons, ready should never be \"true\" for terminating endpoints.",
|
"ready": "ready indicates that this endpoint is prepared to receive traffic, according to whatever system is managing the endpoint. A nil value indicates an unknown state. In most cases consumers should interpret this unknown state as ready. For compatibility reasons, ready should never be \"true\" for terminating endpoints.",
|
||||||
"serving": "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
"serving": "serving is identical to ready except that it is set regardless of the terminating state of endpoints. This condition should be set to true for a ready endpoint that is terminating. If nil, consumers should defer to the ready condition.",
|
||||||
"terminating": "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating. This field can be enabled with the EndpointSliceTerminatingCondition feature gate.",
|
"terminating": "terminating indicates that this endpoint is terminating. A nil value indicates an unknown state. Consumers should interpret this unknown state to mean that the endpoint is not terminating.",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (EndpointConditions) SwaggerDoc() map[string]string {
|
func (EndpointConditions) SwaggerDoc() map[string]string {
|
||||||
|
@ -27,69 +27,24 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
|
||||||
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
||||||
"k8s.io/kubernetes/pkg/controller/endpointslice"
|
"k8s.io/kubernetes/pkg/controller/endpointslice"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
"k8s.io/kubernetes/test/integration/framework"
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
utilpointer "k8s.io/utils/pointer"
|
utilpointer "k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestEndpointSliceTerminating tests that terminating pods are NOT included in EndpointSlice when
|
// TestEndpointSliceTerminating tests that terminating endpoints are included with the
|
||||||
// the feature gate EndpointSliceTerminatingCondition is off. If the gate is on, it tests that
|
// correct conditions set for ready, serving and terminating.
|
||||||
// terminating endpoints are included but with the correct conditions set for ready, serving and terminating.
|
|
||||||
func TestEndpointSliceTerminating(t *testing.T) {
|
func TestEndpointSliceTerminating(t *testing.T) {
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
name string
|
name string
|
||||||
podStatus corev1.PodStatus
|
podStatus corev1.PodStatus
|
||||||
expectedEndpoints []discovery.Endpoint
|
expectedEndpoints []discovery.Endpoint
|
||||||
terminatingGate bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "ready terminating pods not included, terminating gate off",
|
name: "ready terminating pods",
|
||||||
podStatus: corev1.PodStatus{
|
|
||||||
Phase: corev1.PodRunning,
|
|
||||||
Conditions: []corev1.PodCondition{
|
|
||||||
{
|
|
||||||
Type: corev1.PodReady,
|
|
||||||
Status: corev1.ConditionTrue,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PodIP: "10.0.0.1",
|
|
||||||
PodIPs: []corev1.PodIP{
|
|
||||||
{
|
|
||||||
IP: "10.0.0.1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEndpoints: []discovery.Endpoint{},
|
|
||||||
terminatingGate: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "not ready terminating pods not included, terminating gate off",
|
|
||||||
podStatus: corev1.PodStatus{
|
|
||||||
Phase: corev1.PodRunning,
|
|
||||||
Conditions: []corev1.PodCondition{
|
|
||||||
{
|
|
||||||
Type: corev1.PodReady,
|
|
||||||
Status: corev1.ConditionFalse,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PodIP: "10.0.0.1",
|
|
||||||
PodIPs: []corev1.PodIP{
|
|
||||||
{
|
|
||||||
IP: "10.0.0.1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedEndpoints: []discovery.Endpoint{},
|
|
||||||
terminatingGate: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ready terminating pods included, terminating gate on",
|
|
||||||
podStatus: corev1.PodStatus{
|
podStatus: corev1.PodStatus{
|
||||||
Phase: corev1.PodRunning,
|
Phase: corev1.PodRunning,
|
||||||
Conditions: []corev1.PodCondition{
|
Conditions: []corev1.PodCondition{
|
||||||
@ -115,10 +70,9 @@ func TestEndpointSliceTerminating(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
terminatingGate: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "not ready terminating pods included, terminating gate on",
|
name: "not ready terminating pods",
|
||||||
podStatus: corev1.PodStatus{
|
podStatus: corev1.PodStatus{
|
||||||
Phase: corev1.PodRunning,
|
Phase: corev1.PodRunning,
|
||||||
Conditions: []corev1.PodCondition{
|
Conditions: []corev1.PodCondition{
|
||||||
@ -144,14 +98,11 @@ func TestEndpointSliceTerminating(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
terminatingGate: true,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range testcases {
|
for _, testcase := range testcases {
|
||||||
t.Run(testcase.name, func(t *testing.T) {
|
t.Run(testcase.name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testcase.terminatingGate)()
|
|
||||||
|
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
|
server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
|
||||||
defer server.TearDownFn()
|
defer server.TearDownFn()
|
||||||
|
Loading…
Reference in New Issue
Block a user