@@ -3928,7 +3928,7 @@ var supportedServiceType = sets.NewString(string(core.ServiceTypeClusterIP), str
3928
3928
var supportedServiceIPFamily = sets .NewString (string (core .IPv4Protocol ), string (core .IPv6Protocol ))
3929
3929
3930
3930
// ValidateService tests if required fields/annotations of a Service are valid.
3931
- func ValidateService (service * core.Service ) field.ErrorList {
3931
+ func ValidateService (service * core.Service , allowAppProtocol bool ) field.ErrorList {
3932
3932
allErrs := ValidateObjectMeta (& service .ObjectMeta , true , ValidateServiceName , field .NewPath ("metadata" ))
3933
3933
3934
3934
specPath := field .NewPath ("spec" )
@@ -3973,7 +3973,7 @@ func ValidateService(service *core.Service) field.ErrorList {
3973
3973
portsPath := specPath .Child ("ports" )
3974
3974
for i := range service .Spec .Ports {
3975
3975
portPath := portsPath .Index (i )
3976
- allErrs = append (allErrs , validateServicePort (& service .Spec .Ports [i ], len (service .Spec .Ports ) > 1 , isHeadlessService , & allPortNames , portPath )... )
3976
+ allErrs = append (allErrs , validateServicePort (& service .Spec .Ports [i ], len (service .Spec .Ports ) > 1 , isHeadlessService , allowAppProtocol , & allPortNames , portPath )... )
3977
3977
}
3978
3978
3979
3979
if service .Spec .Selector != nil {
@@ -4145,7 +4145,7 @@ func ValidateService(service *core.Service) field.ErrorList {
4145
4145
return allErrs
4146
4146
}
4147
4147
4148
- func validateServicePort (sp * core.ServicePort , requireName , isHeadlessService bool , allNames * sets.String , fldPath * field.Path ) field.ErrorList {
4148
+ func validateServicePort (sp * core.ServicePort , requireName , isHeadlessService , allowAppProtocol bool , allNames * sets.String , fldPath * field.Path ) field.ErrorList {
4149
4149
allErrs := field.ErrorList {}
4150
4150
4151
4151
if requireName && len (sp .Name ) == 0 {
@@ -4171,6 +4171,16 @@ func validateServicePort(sp *core.ServicePort, requireName, isHeadlessService bo
4171
4171
4172
4172
allErrs = append (allErrs , ValidatePortNumOrName (sp .TargetPort , fldPath .Child ("targetPort" ))... )
4173
4173
4174
+ if sp .AppProtocol != nil {
4175
+ if allowAppProtocol {
4176
+ for _ , msg := range validation .IsQualifiedName (* sp .AppProtocol ) {
4177
+ allErrs = append (allErrs , field .Invalid (fldPath .Child ("appProtocol" ), sp .AppProtocol , msg ))
4178
+ }
4179
+ } else {
4180
+ allErrs = append (allErrs , field .Forbidden (fldPath .Child ("appProtocol" ), "This field can be enabled with the ServiceAppProtocol feature gate" ))
4181
+ }
4182
+ }
4183
+
4174
4184
// in the v1 API, targetPorts on headless services were tolerated.
4175
4185
// once we have version-specific validation, we can reject this on newer API versions, but until then, we have to tolerate it for compatibility.
4176
4186
//
@@ -4227,6 +4237,14 @@ func ValidateServiceExternalTrafficFieldsCombination(service *core.Service) fiel
4227
4237
return allErrs
4228
4238
}
4229
4239
4240
+ // ValidateServiceCreate validates Services as they are created.
4241
+ func ValidateServiceCreate (service * core.Service ) field.ErrorList {
4242
+ // allow AppProtocol value if the feature gate is set.
4243
+ allowAppProtocol := utilfeature .DefaultFeatureGate .Enabled (features .ServiceAppProtocol )
4244
+
4245
+ return ValidateService (service , allowAppProtocol )
4246
+ }
4247
+
4230
4248
// ValidateServiceUpdate tests if required fields in the service are set during an update
4231
4249
func ValidateServiceUpdate (service , oldService * core.Service ) field.ErrorList {
4232
4250
allErrs := ValidateObjectMetaUpdate (& service .ObjectMeta , & oldService .ObjectMeta , field .NewPath ("metadata" ))
@@ -4246,8 +4264,19 @@ func ValidateServiceUpdate(service, oldService *core.Service) field.ErrorList {
4246
4264
}
4247
4265
}
4248
4266
4249
- allErrs = append (allErrs , ValidateService (service )... )
4250
- return allErrs
4267
+ // allow AppProtocol value if the feature gate is set or the field is
4268
+ // already set on the resource.
4269
+ allowAppProtocol := utilfeature .DefaultFeatureGate .Enabled (features .ServiceAppProtocol )
4270
+ if ! allowAppProtocol {
4271
+ for _ , port := range oldService .Spec .Ports {
4272
+ if port .AppProtocol != nil {
4273
+ allowAppProtocol = true
4274
+ break
4275
+ }
4276
+ }
4277
+ }
4278
+
4279
+ return append (allErrs , ValidateService (service , allowAppProtocol )... )
4251
4280
}
4252
4281
4253
4282
// ValidateServiceStatusUpdate tests if required fields in the Service are set when updating status.
@@ -5463,15 +5492,42 @@ func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *core.Namespace)
5463
5492
return allErrs
5464
5493
}
5465
5494
5466
- // ValidateEndpoints tests if required fields are set .
5467
- func ValidateEndpoints (endpoints * core.Endpoints ) field.ErrorList {
5495
+ // ValidateEndpoints validates Endpoints on create and update .
5496
+ func ValidateEndpoints (endpoints * core.Endpoints , allowAppProtocol bool ) field.ErrorList {
5468
5497
allErrs := ValidateObjectMeta (& endpoints .ObjectMeta , true , ValidateEndpointsName , field .NewPath ("metadata" ))
5469
5498
allErrs = append (allErrs , ValidateEndpointsSpecificAnnotations (endpoints .Annotations , field .NewPath ("annotations" ))... )
5470
- allErrs = append (allErrs , validateEndpointSubsets (endpoints .Subsets , field .NewPath ("subsets" ))... )
5499
+ allErrs = append (allErrs , validateEndpointSubsets (endpoints .Subsets , allowAppProtocol , field .NewPath ("subsets" ))... )
5500
+ return allErrs
5501
+ }
5502
+
5503
+ // ValidateEndpointsCreate validates Endpoints on create.
5504
+ func ValidateEndpointsCreate (endpoints * core.Endpoints ) field.ErrorList {
5505
+ allowAppProtocol := utilfeature .DefaultFeatureGate .Enabled (features .ServiceAppProtocol )
5506
+ return ValidateEndpoints (endpoints , allowAppProtocol )
5507
+ }
5508
+
5509
+ // ValidateEndpointsUpdate validates Endpoints on update. NodeName changes are
5510
+ // allowed during update to accommodate the case where nodeIP or PodCIDR is
5511
+ // reused. An existing endpoint ip will have a different nodeName if this
5512
+ // happens.
5513
+ func ValidateEndpointsUpdate (newEndpoints , oldEndpoints * core.Endpoints ) field.ErrorList {
5514
+ allErrs := ValidateObjectMetaUpdate (& newEndpoints .ObjectMeta , & oldEndpoints .ObjectMeta , field .NewPath ("metadata" ))
5515
+ allowAppProtocol := utilfeature .DefaultFeatureGate .Enabled (features .ServiceAppProtocol )
5516
+ if ! allowAppProtocol {
5517
+ for _ , oldSubset := range oldEndpoints .Subsets {
5518
+ for _ , port := range oldSubset .Ports {
5519
+ if port .AppProtocol != nil {
5520
+ allowAppProtocol = true
5521
+ break
5522
+ }
5523
+ }
5524
+ }
5525
+ }
5526
+ allErrs = append (allErrs , ValidateEndpoints (newEndpoints , allowAppProtocol )... )
5471
5527
return allErrs
5472
5528
}
5473
5529
5474
- func validateEndpointSubsets (subsets []core.EndpointSubset , fldPath * field.Path ) field.ErrorList {
5530
+ func validateEndpointSubsets (subsets []core.EndpointSubset , allowAppProtocol bool , fldPath * field.Path ) field.ErrorList {
5475
5531
allErrs := field.ErrorList {}
5476
5532
for i := range subsets {
5477
5533
ss := & subsets [i ]
@@ -5489,7 +5545,7 @@ func validateEndpointSubsets(subsets []core.EndpointSubset, fldPath *field.Path)
5489
5545
allErrs = append (allErrs , validateEndpointAddress (& ss .NotReadyAddresses [addr ], idxPath .Child ("notReadyAddresses" ).Index (addr ))... )
5490
5546
}
5491
5547
for port := range ss .Ports {
5492
- allErrs = append (allErrs , validateEndpointPort (& ss .Ports [port ], len (ss .Ports ) > 1 , idxPath .Child ("ports" ).Index (port ))... )
5548
+ allErrs = append (allErrs , validateEndpointPort (& ss .Ports [port ], len (ss .Ports ) > 1 , allowAppProtocol , idxPath .Child ("ports" ).Index (port ))... )
5493
5549
}
5494
5550
}
5495
5551
@@ -5540,7 +5596,7 @@ func validateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList
5540
5596
return allErrs
5541
5597
}
5542
5598
5543
- func validateEndpointPort (port * core.EndpointPort , requireName bool , fldPath * field.Path ) field.ErrorList {
5599
+ func validateEndpointPort (port * core.EndpointPort , requireName , allowAppProtocol bool , fldPath * field.Path ) field.ErrorList {
5544
5600
allErrs := field.ErrorList {}
5545
5601
if requireName && len (port .Name ) == 0 {
5546
5602
allErrs = append (allErrs , field .Required (fldPath .Child ("name" ), "" ))
@@ -5555,16 +5611,15 @@ func validateEndpointPort(port *core.EndpointPort, requireName bool, fldPath *fi
5555
5611
} else if ! supportedPortProtocols .Has (string (port .Protocol )) {
5556
5612
allErrs = append (allErrs , field .NotSupported (fldPath .Child ("protocol" ), port .Protocol , supportedPortProtocols .List ()))
5557
5613
}
5558
- return allErrs
5559
- }
5560
-
5561
- // ValidateEndpointsUpdate tests to make sure an endpoints update can be applied.
5562
- // NodeName changes are allowed during update to accommodate the case where nodeIP or PodCIDR is reused.
5563
- // An existing endpoint ip will have a different nodeName if this happens.
5564
- func ValidateEndpointsUpdate (newEndpoints , oldEndpoints * core.Endpoints ) field.ErrorList {
5565
- allErrs := ValidateObjectMetaUpdate (& newEndpoints .ObjectMeta , & oldEndpoints .ObjectMeta , field .NewPath ("metadata" ))
5566
- allErrs = append (allErrs , validateEndpointSubsets (newEndpoints .Subsets , field .NewPath ("subsets" ))... )
5567
- allErrs = append (allErrs , ValidateEndpointsSpecificAnnotations (newEndpoints .Annotations , field .NewPath ("annotations" ))... )
5614
+ if port .AppProtocol != nil {
5615
+ if allowAppProtocol {
5616
+ for _ , msg := range validation .IsQualifiedName (* port .AppProtocol ) {
5617
+ allErrs = append (allErrs , field .Invalid (fldPath .Child ("appProtocol" ), port .AppProtocol , msg ))
5618
+ }
5619
+ } else {
5620
+ allErrs = append (allErrs , field .Forbidden (fldPath .Child ("appProtocol" ), "This field can be enabled with the ServiceAppProtocol feature gate" ))
5621
+ }
5622
+ }
5568
5623
return allErrs
5569
5624
}
5570
5625
0 commit comments