diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 50260b960bc..dda18711e65 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -1239,9 +1239,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 { @@ -1309,7 +1311,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 == "" { @@ -1341,6 +1343,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 71b39eae611..3fa41fbbe7b 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -1874,6 +1874,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) {