diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index e78095393c8..570879717f3 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -1253,9 +1253,11 @@ func ValidateService(service *api.Service) validation.ErrorList { } } } + + isHeadlessService := service.Spec.ClusterIP == api.ClusterIPNone allPortNames := sets.String{} for i := range service.Spec.Ports { - allErrs = append(allErrs, validateServicePort(&service.Spec.Ports[i], len(service.Spec.Ports) > 1, &allPortNames).PrefixIndex(i).Prefix("spec.ports")...) + allErrs = append(allErrs, validateServicePort(&service.Spec.Ports[i], len(service.Spec.Ports) > 1, isHeadlessService, &allPortNames).PrefixIndex(i).Prefix("spec.ports")...) } if service.Spec.Selector != nil { @@ -1323,7 +1325,7 @@ func ValidateService(service *api.Service) validation.ErrorList { return allErrs } -func validateServicePort(sp *api.ServicePort, requireName bool, allNames *sets.String) validation.ErrorList { +func validateServicePort(sp *api.ServicePort, requireName, isHeadlessService bool, allNames *sets.String) validation.ErrorList { allErrs := validation.ErrorList{} if requireName && sp.Name == "" { @@ -1355,6 +1357,12 @@ func validateServicePort(sp *api.ServicePort, requireName bool, allNames *sets.S allErrs = append(allErrs, validation.NewInvalidError("targetPort", sp.TargetPort, PortNameErrorMsg)) } + if isHeadlessService { + if sp.TargetPort.Type == intstr.String || (sp.TargetPort.Type == intstr.Int && sp.Port != sp.TargetPort.IntValue()) { + allErrs = append(allErrs, validation.NewInvalidError("port", sp.Port, "must be equal to targetPort when clusterIP = None")) + } + } + return allErrs } diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index 87af9ee5870..3419ae80e7a 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -1881,6 +1881,33 @@ func TestValidateService(t *testing.T) { }, numErrs: 1, }, + { + name: "valid port headless", + tweakSvc: func(s *api.Service) { + s.Spec.Ports[0].Port = 11722 + s.Spec.Ports[0].TargetPort = intstr.FromInt(11722) + s.Spec.ClusterIP = api.ClusterIPNone + }, + numErrs: 0, + }, + { + name: "invalid port headless", + tweakSvc: func(s *api.Service) { + s.Spec.Ports[0].Port = 11722 + s.Spec.Ports[0].TargetPort = intstr.FromInt(11721) + s.Spec.ClusterIP = api.ClusterIPNone + }, + numErrs: 1, + }, + { + name: "invalid port headless", + tweakSvc: func(s *api.Service) { + s.Spec.Ports[0].Port = 11722 + s.Spec.Ports[0].TargetPort = intstr.FromString("target") + s.Spec.ClusterIP = api.ClusterIPNone + }, + numErrs: 1, + }, { name: "invalid publicIPs localhost", tweakSvc: func(s *api.Service) {