Gate: disallow .status.loadBalancer on non-LB svc

The fact that the .status.loadBalancer field can be set while .spec.type
is not "LoadBalancer" is a flub.  Any spec update will already clear
.status.ingress, so it's hard to really rely on this.  After this
change, updates which try to set this combination will fail validation.

Existing cases of this will not be broken.  Any spec/metadata update
will clear it (no error) and this is the only stanza of status.

New gate "AllowServiceLBStatusOnNonLB" is off by default, but can be
enabled if this change actually breaks someone, which seems exceeedingly
unlikely.
This commit is contained in:
Tim Hockin
2023-08-06 16:53:10 -07:00
parent 2979242743
commit a930892769
6 changed files with 75 additions and 30 deletions

View File

@@ -23377,11 +23377,36 @@ func TestValidateLoadBalancerStatus(t *testing.T) {
testCases := []struct {
name string
ipModeEnabled bool
nonLBAllowed bool
tweakLBStatus func(s *core.LoadBalancerStatus)
tweakSvcSpec func(s *core.ServiceSpec)
numErrs int
}{
/* LoadBalancerIPMode*/
{
name: "type is not LB",
nonLBAllowed: false,
tweakSvcSpec: func(s *core.ServiceSpec) {
s.Type = core.ServiceTypeClusterIP
},
tweakLBStatus: func(s *core.LoadBalancerStatus) {
s.Ingress = []core.LoadBalancerIngress{{
IP: "1.2.3.4",
}}
},
numErrs: 1,
}, {
name: "type is not LB. back-compat",
nonLBAllowed: true,
tweakSvcSpec: func(s *core.ServiceSpec) {
s.Type = core.ServiceTypeClusterIP
},
tweakLBStatus: func(s *core.LoadBalancerStatus) {
s.Ingress = []core.LoadBalancerIngress{{
IP: "1.2.3.4",
}}
},
numErrs: 0,
}, {
name: "valid vip ipMode",
ipModeEnabled: true,
tweakLBStatus: func(s *core.LoadBalancerStatus) {
@@ -23443,9 +23468,14 @@ func TestValidateLoadBalancerStatus(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LoadBalancerIPMode, tc.ipModeEnabled)()
s := core.LoadBalancerStatus{}
tc.tweakLBStatus(&s)
errs := ValidateLoadBalancerStatus(&s, field.NewPath("status"))
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AllowServiceLBStatusOnNonLB, tc.nonLBAllowed)()
status := core.LoadBalancerStatus{}
tc.tweakLBStatus(&status)
spec := core.ServiceSpec{Type: core.ServiceTypeLoadBalancer}
if tc.tweakSvcSpec != nil {
tc.tweakSvcSpec(&spec)
}
errs := ValidateLoadBalancerStatus(&status, field.NewPath("status"), &spec)
if len(errs) != tc.numErrs {
t.Errorf("Unexpected error list for case %q(expected:%v got %v) - Errors:\n %v", tc.name, tc.numErrs, len(errs), errs.ToAggregate())
}