@@ -3908,7 +3908,7 @@ var supportedServiceType = sets.NewString(string(core.ServiceTypeClusterIP), str
3908
3908
var supportedServiceIPFamily = sets .NewString (string (core .IPv4Protocol ), string (core .IPv6Protocol ))
3909
3909
3910
3910
// ValidateService tests if required fields/annotations of a Service are valid.
3911
- func ValidateService (service * core.Service ) field.ErrorList {
3911
+ func ValidateService (service * core.Service , allowAppProtocol bool ) field.ErrorList {
3912
3912
allErrs := ValidateObjectMeta (& service .ObjectMeta , true , ValidateServiceName , field .NewPath ("metadata" ))
3913
3913
3914
3914
specPath := field .NewPath ("spec" )
@@ -3953,7 +3953,7 @@ func ValidateService(service *core.Service) field.ErrorList {
3953
3953
portsPath := specPath .Child ("ports" )
3954
3954
for i := range service .Spec .Ports {
3955
3955
portPath := portsPath .Index (i )
3956
- allErrs = append (allErrs , validateServicePort (& service .Spec .Ports [i ], len (service .Spec .Ports ) > 1 , isHeadlessService , & allPortNames , portPath )... )
3956
+ allErrs = append (allErrs , validateServicePort (& service .Spec .Ports [i ], len (service .Spec .Ports ) > 1 , isHeadlessService , allowAppProtocol , & allPortNames , portPath )... )
3957
3957
}
3958
3958
3959
3959
if service .Spec .Selector != nil {
@@ -4125,7 +4125,7 @@ func ValidateService(service *core.Service) field.ErrorList {
4125
4125
return allErrs
4126
4126
}
4127
4127
4128
- func validateServicePort (sp * core.ServicePort , requireName , isHeadlessService bool , allNames * sets.String , fldPath * field.Path ) field.ErrorList {
4128
+ func validateServicePort (sp * core.ServicePort , requireName , isHeadlessService , allowAppProtocol bool , allNames * sets.String , fldPath * field.Path ) field.ErrorList {
4129
4129
allErrs := field.ErrorList {}
4130
4130
4131
4131
if requireName && len (sp .Name ) == 0 {
@@ -4151,6 +4151,16 @@ func validateServicePort(sp *core.ServicePort, requireName, isHeadlessService bo
4151
4151
4152
4152
allErrs = append (allErrs , ValidatePortNumOrName (sp .TargetPort , fldPath .Child ("targetPort" ))... )
4153
4153
4154
+ if sp .AppProtocol != nil {
4155
+ if allowAppProtocol {
4156
+ for _ , msg := range validation .IsQualifiedName (* sp .AppProtocol ) {
4157
+ allErrs = append (allErrs , field .Invalid (fldPath .Child ("appProtocol" ), sp .AppProtocol , msg ))
4158
+ }
4159
+ } else {
4160
+ allErrs = append (allErrs , field .Forbidden (fldPath .Child ("appProtocol" ), "This field can be enabled with the ServiceAppProtocol feature gate" ))
4161
+ }
4162
+ }
4163
+
4154
4164
// in the v1 API, targetPorts on headless services were tolerated.
4155
4165
// once we have version-specific validation, we can reject this on newer API versions, but until then, we have to tolerate it for compatibility.
4156
4166
//
@@ -4207,6 +4217,14 @@ func ValidateServiceExternalTrafficFieldsCombination(service *core.Service) fiel
4207
4217
return allErrs
4208
4218
}
4209
4219
4220
+ // ValidateServiceCreate validates Services as they are created.
4221
+ func ValidateServiceCreate (service * core.Service ) field.ErrorList {
4222
+ // allow AppProtocol value if the feature gate is set.
4223
+ allowAppProtocol := utilfeature .DefaultFeatureGate .Enabled (features .ServiceAppProtocol )
4224
+
4225
+ return ValidateService (service , allowAppProtocol )
4226
+ }
4227
+
4210
4228
// ValidateServiceUpdate tests if required fields in the service are set during an update
4211
4229
func ValidateServiceUpdate (service , oldService * core.Service ) field.ErrorList {
4212
4230
allErrs := ValidateObjectMetaUpdate (& service .ObjectMeta , & oldService .ObjectMeta , field .NewPath ("metadata" ))
@@ -4226,8 +4244,19 @@ func ValidateServiceUpdate(service, oldService *core.Service) field.ErrorList {
4226
4244
}
4227
4245
}
4228
4246
4229
- allErrs = append (allErrs , ValidateService (service )... )
4230
- return allErrs
4247
+ // allow AppProtocol value if the feature gate is set or the field is
4248
+ // already set on the resource.
4249
+ allowAppProtocol := utilfeature .DefaultFeatureGate .Enabled (features .ServiceAppProtocol )
4250
+ if ! allowAppProtocol {
4251
+ for _ , port := range oldService .Spec .Ports {
4252
+ if port .AppProtocol != nil {
4253
+ allowAppProtocol = true
4254
+ break
4255
+ }
4256
+ }
4257
+ }
4258
+
4259
+ return append (allErrs , ValidateService (service , allowAppProtocol )... )
4231
4260
}
4232
4261
4233
4262
// ValidateServiceStatusUpdate tests if required fields in the Service are set when updating status.
@@ -5443,15 +5472,42 @@ func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *core.Namespace)
5443
5472
return allErrs
5444
5473
}
5445
5474
5446
- // ValidateEndpoints tests if required fields are set .
5447
- func ValidateEndpoints (endpoints * core.Endpoints ) field.ErrorList {
5475
+ // ValidateEndpoints validates Endpoints on create and update .
5476
+ func ValidateEndpoints (endpoints * core.Endpoints , allowAppProtocol bool ) field.ErrorList {
5448
5477
allErrs := ValidateObjectMeta (& endpoints .ObjectMeta , true , ValidateEndpointsName , field .NewPath ("metadata" ))
5449
5478
allErrs = append (allErrs , ValidateEndpointsSpecificAnnotations (endpoints .Annotations , field .NewPath ("annotations" ))... )
5450
- allErrs = append (allErrs , validateEndpointSubsets (endpoints .Subsets , field .NewPath ("subsets" ))... )
5479
+ allErrs = append (allErrs , validateEndpointSubsets (endpoints .Subsets , allowAppProtocol , field .NewPath ("subsets" ))... )
5480
+ return allErrs
5481
+ }
5482
+
5483
+ // ValidateEndpointsCreate validates Endpoints on create.
5484
+ func ValidateEndpointsCreate (endpoints * core.Endpoints ) field.ErrorList {
5485
+ allowAppProtocol := utilfeature .DefaultFeatureGate .Enabled (features .ServiceAppProtocol )
5486
+ return ValidateEndpoints (endpoints , allowAppProtocol )
5487
+ }
5488
+
5489
+ // ValidateEndpointsUpdate validates Endpoints on update. NodeName changes are
5490
+ // allowed during update to accommodate the case where nodeIP or PodCIDR is
5491
+ // reused. An existing endpoint ip will have a different nodeName if this
5492
+ // happens.
5493
+ func ValidateEndpointsUpdate (newEndpoints , oldEndpoints * core.Endpoints ) field.ErrorList {
5494
+ allErrs := ValidateObjectMetaUpdate (& newEndpoints .ObjectMeta , & oldEndpoints .ObjectMeta , field .NewPath ("metadata" ))
5495
+ allowAppProtocol := utilfeature .DefaultFeatureGate .Enabled (features .ServiceAppProtocol )
5496
+ if ! allowAppProtocol {
5497
+ for _ , oldSubset := range oldEndpoints .Subsets {
5498
+ for _ , port := range oldSubset .Ports {
5499
+ if port .AppProtocol != nil {
5500
+ allowAppProtocol = true
5501
+ break
5502
+ }
5503
+ }
5504
+ }
5505
+ }
5506
+ allErrs = append (allErrs , ValidateEndpoints (newEndpoints , allowAppProtocol )... )
5451
5507
return allErrs
5452
5508
}
5453
5509
5454
- func validateEndpointSubsets (subsets []core.EndpointSubset , fldPath * field.Path ) field.ErrorList {
5510
+ func validateEndpointSubsets (subsets []core.EndpointSubset , allowAppProtocol bool , fldPath * field.Path ) field.ErrorList {
5455
5511
allErrs := field.ErrorList {}
5456
5512
for i := range subsets {
5457
5513
ss := & subsets [i ]
@@ -5469,7 +5525,7 @@ func validateEndpointSubsets(subsets []core.EndpointSubset, fldPath *field.Path)
5469
5525
allErrs = append (allErrs , validateEndpointAddress (& ss .NotReadyAddresses [addr ], idxPath .Child ("notReadyAddresses" ).Index (addr ))... )
5470
5526
}
5471
5527
for port := range ss .Ports {
5472
- allErrs = append (allErrs , validateEndpointPort (& ss .Ports [port ], len (ss .Ports ) > 1 , idxPath .Child ("ports" ).Index (port ))... )
5528
+ allErrs = append (allErrs , validateEndpointPort (& ss .Ports [port ], len (ss .Ports ) > 1 , allowAppProtocol , idxPath .Child ("ports" ).Index (port ))... )
5473
5529
}
5474
5530
}
5475
5531
@@ -5520,7 +5576,7 @@ func validateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList
5520
5576
return allErrs
5521
5577
}
5522
5578
5523
- func validateEndpointPort (port * core.EndpointPort , requireName bool , fldPath * field.Path ) field.ErrorList {
5579
+ func validateEndpointPort (port * core.EndpointPort , requireName , allowAppProtocol bool , fldPath * field.Path ) field.ErrorList {
5524
5580
allErrs := field.ErrorList {}
5525
5581
if requireName && len (port .Name ) == 0 {
5526
5582
allErrs = append (allErrs , field .Required (fldPath .Child ("name" ), "" ))
@@ -5535,16 +5591,15 @@ func validateEndpointPort(port *core.EndpointPort, requireName bool, fldPath *fi
5535
5591
} else if ! supportedPortProtocols .Has (string (port .Protocol )) {
5536
5592
allErrs = append (allErrs , field .NotSupported (fldPath .Child ("protocol" ), port .Protocol , supportedPortProtocols .List ()))
5537
5593
}
5538
- return allErrs
5539
- }
5540
-
5541
- // ValidateEndpointsUpdate tests to make sure an endpoints update can be applied.
5542
- // NodeName changes are allowed during update to accommodate the case where nodeIP or PodCIDR is reused.
5543
- // An existing endpoint ip will have a different nodeName if this happens.
5544
- func ValidateEndpointsUpdate (newEndpoints , oldEndpoints * core.Endpoints ) field.ErrorList {
5545
- allErrs := ValidateObjectMetaUpdate (& newEndpoints .ObjectMeta , & oldEndpoints .ObjectMeta , field .NewPath ("metadata" ))
5546
- allErrs = append (allErrs , validateEndpointSubsets (newEndpoints .Subsets , field .NewPath ("subsets" ))... )
5547
- allErrs = append (allErrs , ValidateEndpointsSpecificAnnotations (newEndpoints .Annotations , field .NewPath ("annotations" ))... )
5594
+ if port .AppProtocol != nil {
5595
+ if allowAppProtocol {
5596
+ for _ , msg := range validation .IsQualifiedName (* port .AppProtocol ) {
5597
+ allErrs = append (allErrs , field .Invalid (fldPath .Child ("appProtocol" ), port .AppProtocol , msg ))
5598
+ }
5599
+ } else {
5600
+ allErrs = append (allErrs , field .Forbidden (fldPath .Child ("appProtocol" ), "This field can be enabled with the ServiceAppProtocol feature gate" ))
5601
+ }
5602
+ }
5548
5603
return allErrs
5549
5604
}
5550
5605
0 commit comments