Adding AppProtocol to Service and Endpoints Ports
This commit is contained in:
@@ -65,6 +65,7 @@ go_test(
|
||||
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
||||
"//vendor/k8s.io/utils/pointer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -444,17 +444,14 @@ func (e *EndpointController) syncService(key string) error {
|
||||
} else {
|
||||
for i := range service.Spec.Ports {
|
||||
servicePort := &service.Spec.Ports[i]
|
||||
|
||||
portName := servicePort.Name
|
||||
portProto := servicePort.Protocol
|
||||
portNum, err := podutil.FindPort(pod, servicePort)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("Failed to find port for service %s/%s: %v", service.Namespace, service.Name, err)
|
||||
continue
|
||||
}
|
||||
epp := endpointPortFromServicePort(servicePort, portNum)
|
||||
|
||||
var readyEps, notReadyEps int
|
||||
epp := &v1.EndpointPort{Name: portName, Port: int32(portNum), Protocol: portProto}
|
||||
subsets, readyEps, notReadyEps = addEndpointSubset(subsets, pod, epa, epp, tolerateUnreadyEndpoints)
|
||||
totalReadyEps = totalReadyEps + readyEps
|
||||
totalNotReadyEps = totalNotReadyEps + notReadyEps
|
||||
@@ -608,3 +605,15 @@ func shouldPodBeInEndpoints(pod *v1.Pod) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func endpointPortFromServicePort(servicePort *v1.ServicePort, portNum int) *v1.EndpointPort {
|
||||
epp := &v1.EndpointPort{
|
||||
Name: servicePort.Name,
|
||||
Port: int32(portNum),
|
||||
Protocol: servicePort.Protocol,
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceAppProtocol) {
|
||||
epp.AppProtocol = servicePort.AppProtocol
|
||||
}
|
||||
return epp
|
||||
}
|
||||
|
@@ -45,6 +45,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
var alwaysReady = func() bool { return true }
|
||||
@@ -1947,6 +1948,55 @@ func TestSyncEndpointsServiceNotFound(t *testing.T) {
|
||||
endpointsHandler.ValidateRequest(t, "/api/v1/namespaces/"+ns+"/endpoints/foo", "DELETE", nil)
|
||||
}
|
||||
|
||||
func TestEndpointPortFromServicePort(t *testing.T) {
|
||||
http := utilpointer.StringPtr("http")
|
||||
testCases := map[string]struct {
|
||||
featureGateEnabled bool
|
||||
serviceAppProtocol *string
|
||||
expectedEndpointsAppProtocol *string
|
||||
}{
|
||||
"feature gate disabled, empty app protocol": {
|
||||
featureGateEnabled: false,
|
||||
serviceAppProtocol: nil,
|
||||
expectedEndpointsAppProtocol: nil,
|
||||
},
|
||||
"feature gate disabled, http app protocol": {
|
||||
featureGateEnabled: false,
|
||||
serviceAppProtocol: http,
|
||||
expectedEndpointsAppProtocol: nil,
|
||||
},
|
||||
"feature gate enabled, empty app protocol": {
|
||||
featureGateEnabled: true,
|
||||
serviceAppProtocol: nil,
|
||||
expectedEndpointsAppProtocol: nil,
|
||||
},
|
||||
"feature gate enabled, http app protocol": {
|
||||
featureGateEnabled: true,
|
||||
serviceAppProtocol: http,
|
||||
expectedEndpointsAppProtocol: http,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceAppProtocol, tc.featureGateEnabled)()
|
||||
|
||||
epp := endpointPortFromServicePort(&v1.ServicePort{Name: "test", AppProtocol: tc.serviceAppProtocol}, 80)
|
||||
|
||||
if epp.AppProtocol != tc.expectedEndpointsAppProtocol {
|
||||
t.Errorf("Expected Endpoints AppProtocol to be %s, got %s", stringVal(tc.expectedEndpointsAppProtocol), stringVal(epp.AppProtocol))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func stringVal(str *string) string {
|
||||
if str == nil {
|
||||
return "nil"
|
||||
}
|
||||
return *str
|
||||
}
|
||||
|
||||
func podChangedHelper(oldPod, newPod *v1.Pod, endpointChanged endpointutil.EndpointsMatch) bool {
|
||||
podChanged, _ := endpointutil.PodChanged(oldPod, newPod, endpointChanged)
|
||||
return podChanged
|
||||
|
@@ -117,9 +117,10 @@ func getEndpointPorts(service *corev1.Service, pod *corev1.Pod) []discovery.Endp
|
||||
|
||||
i32PortNum := int32(portNum)
|
||||
endpointPorts = append(endpointPorts, discovery.EndpointPort{
|
||||
Name: &portName,
|
||||
Port: &i32PortNum,
|
||||
Protocol: &portProto,
|
||||
Name: &portName,
|
||||
Port: &i32PortNum,
|
||||
Protocol: &portProto,
|
||||
AppProtocol: servicePort.AppProtocol,
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -353,6 +353,97 @@ func TestServiceControllerKey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEndpointPorts(t *testing.T) {
|
||||
protoTCP := v1.ProtocolTCP
|
||||
|
||||
testCases := map[string]struct {
|
||||
service *v1.Service
|
||||
pod *v1.Pod
|
||||
expectedPorts []*discovery.EndpointPort
|
||||
}{
|
||||
"service with AppProtocol on one port": {
|
||||
service: &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Ports: []v1.ServicePort{{
|
||||
Name: "http",
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromInt(80),
|
||||
Protocol: protoTCP,
|
||||
AppProtocol: utilpointer.StringPtr("example.com/custom-protocol"),
|
||||
}},
|
||||
},
|
||||
},
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{{
|
||||
Ports: []v1.ContainerPort{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
expectedPorts: []*discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Port: utilpointer.Int32Ptr(80),
|
||||
Protocol: &protoTCP,
|
||||
AppProtocol: utilpointer.StringPtr("example.com/custom-protocol"),
|
||||
}},
|
||||
},
|
||||
"service with named port and AppProtocol on one port": {
|
||||
service: &v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Ports: []v1.ServicePort{{
|
||||
Name: "http",
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromInt(80),
|
||||
Protocol: protoTCP,
|
||||
}, {
|
||||
Name: "https",
|
||||
Protocol: protoTCP,
|
||||
TargetPort: intstr.FromString("https"),
|
||||
AppProtocol: utilpointer.StringPtr("https"),
|
||||
}},
|
||||
},
|
||||
},
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{{
|
||||
Ports: []v1.ContainerPort{{
|
||||
Name: "https",
|
||||
ContainerPort: int32(443),
|
||||
Protocol: protoTCP,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
expectedPorts: []*discovery.EndpointPort{{
|
||||
Name: utilpointer.StringPtr("http"),
|
||||
Port: utilpointer.Int32Ptr(80),
|
||||
Protocol: &protoTCP,
|
||||
}, {
|
||||
Name: utilpointer.StringPtr("https"),
|
||||
Port: utilpointer.Int32Ptr(443),
|
||||
Protocol: &protoTCP,
|
||||
AppProtocol: utilpointer.StringPtr("https"),
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
actualPorts := getEndpointPorts(tc.service, tc.pod)
|
||||
|
||||
if len(actualPorts) != len(tc.expectedPorts) {
|
||||
t.Fatalf("Expected %d ports, got %d", len(tc.expectedPorts), len(actualPorts))
|
||||
}
|
||||
|
||||
for i, actualPort := range actualPorts {
|
||||
if !reflect.DeepEqual(&actualPort, tc.expectedPorts[i]) {
|
||||
t.Errorf("Expected port: %+v, got %+v", tc.expectedPorts[i], &actualPort)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test helpers
|
||||
|
||||
func newPod(n int, namespace string, ready bool, nPorts int) *v1.Pod {
|
||||
|
Reference in New Issue
Block a user