Updating EndpointSlice strategy to cover alpha NodeName field

This commit is contained in:
Rob Scott 2020-11-11 11:17:09 -08:00
parent ff46573692
commit b98cab7740
No known key found for this signature in database
GPG Key ID: 90C19B2D4A99C91B
2 changed files with 208 additions and 39 deletions

View File

@ -50,7 +50,7 @@ func (endpointSliceStrategy) PrepareForCreate(ctx context.Context, obj runtime.O
endpointSlice := obj.(*discovery.EndpointSlice) endpointSlice := obj.(*discovery.EndpointSlice)
endpointSlice.Generation = 1 endpointSlice.Generation = 1
dropDisabledConditionsOnCreate(endpointSlice) dropDisabledFieldsOnCreate(endpointSlice)
} }
// PrepareForUpdate clears fields that are not allowed to be set by end users on update. // PrepareForUpdate clears fields that are not allowed to be set by end users on update.
@ -72,7 +72,7 @@ func (endpointSliceStrategy) PrepareForUpdate(ctx context.Context, obj, old runt
newEPS.ObjectMeta = ogNewMeta newEPS.ObjectMeta = ogNewMeta
oldEPS.ObjectMeta = ogOldMeta oldEPS.ObjectMeta = ogOldMeta
dropDisabledConditionsOnUpdate(oldEPS, newEPS) dropDisabledFieldsOnUpdate(oldEPS, newEPS)
} }
// Validate validates a new EndpointSlice. // Validate validates a new EndpointSlice.
@ -103,41 +103,56 @@ func (endpointSliceStrategy) AllowUnconditionalUpdate() bool {
return true return true
} }
// dropDisabledConditionsOnCreate will drop the terminating condition if the // dropDisabledConditionsOnCreate will drop any fields that are disabled.
// EndpointSliceTerminatingCondition is disabled. Otherwise the field is left untouched. func dropDisabledFieldsOnCreate(endpointSlice *discovery.EndpointSlice) {
func dropDisabledConditionsOnCreate(endpointSlice *discovery.EndpointSlice) { dropNodeName := !utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceNodeName)
if utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceTerminatingCondition) { dropTerminating := !utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceTerminatingCondition)
return
}
// Always drop the serving/terminating conditions on create when feature gate is disabled. if dropNodeName || dropTerminating {
for i := range endpointSlice.Endpoints { for i := range endpointSlice.Endpoints {
if dropNodeName {
endpointSlice.Endpoints[i].NodeName = nil
}
if dropTerminating {
endpointSlice.Endpoints[i].Conditions.Serving = nil endpointSlice.Endpoints[i].Conditions.Serving = nil
endpointSlice.Endpoints[i].Conditions.Terminating = nil endpointSlice.Endpoints[i].Conditions.Terminating = nil
} }
}
}
} }
// dropDisabledConditionsOnUpdate will drop the terminating condition field if the EndpointSliceTerminatingCondition // dropDisabledFieldsOnUpdate will drop any disable fields that have not already
// feature gate is disabled unless an existing EndpointSlice object has the field already set. This ensures // been set on the EndpointSlice.
// the field is not dropped on rollback. func dropDisabledFieldsOnUpdate(oldEPS, newEPS *discovery.EndpointSlice) {
func dropDisabledConditionsOnUpdate(oldEPS, newEPS *discovery.EndpointSlice) { dropNodeName := !utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceNodeName)
if utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceTerminatingCondition) { if dropNodeName {
return
}
// Only drop the serving/terminating condition if the existing EndpointSlice doesn't have it set.
dropConditions := true
for _, ep := range oldEPS.Endpoints { for _, ep := range oldEPS.Endpoints {
if ep.Conditions.Serving != nil || ep.Conditions.Terminating != nil { if ep.NodeName != nil {
dropConditions = false dropNodeName = false
break break
} }
} }
}
if dropConditions { dropTerminating := !utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceTerminatingCondition)
if dropTerminating {
for _, ep := range oldEPS.Endpoints {
if ep.Conditions.Serving != nil || ep.Conditions.Terminating != nil {
dropTerminating = false
break
}
}
}
if dropNodeName || dropTerminating {
for i := range newEPS.Endpoints { for i := range newEPS.Endpoints {
if dropNodeName {
newEPS.Endpoints[i].NodeName = nil
}
if dropTerminating {
newEPS.Endpoints[i].Conditions.Serving = nil newEPS.Endpoints[i].Conditions.Serving = nil
newEPS.Endpoints[i].Conditions.Terminating = nil newEPS.Endpoints[i].Conditions.Terminating = nil
} }
} }
}
} }

View File

@ -27,15 +27,16 @@ import (
utilpointer "k8s.io/utils/pointer" utilpointer "k8s.io/utils/pointer"
) )
func Test_dropConditionsOnCreate(t *testing.T) { func Test_dropDisabledFieldsOnCreate(t *testing.T) {
testcases := []struct { testcases := []struct {
name string name string
terminatingGateEnabled bool terminatingGateEnabled bool
nodeNameGateEnabled bool
eps *discovery.EndpointSlice eps *discovery.EndpointSlice
expectedEPS *discovery.EndpointSlice expectedEPS *discovery.EndpointSlice
}{ }{
{ {
name: "gate enabled, field should be allowed", name: "terminating gate enabled, field should be allowed",
terminatingGateEnabled: true, terminatingGateEnabled: true,
eps: &discovery.EndpointSlice{ eps: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{ Endpoints: []discovery.Endpoint{
@ -83,7 +84,7 @@ func Test_dropConditionsOnCreate(t *testing.T) {
}, },
}, },
{ {
name: "gate disabled, field should be set to nil", name: "terminating gate disabled, field should be set to nil",
terminatingGateEnabled: false, terminatingGateEnabled: false,
eps: &discovery.EndpointSlice{ eps: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{ Endpoints: []discovery.Endpoint{
@ -130,13 +131,62 @@ func Test_dropConditionsOnCreate(t *testing.T) {
}, },
}, },
}, },
{
name: "node name gate enabled, field should be allowed",
nodeNameGateEnabled: true,
eps: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: utilpointer.StringPtr("node-1"),
},
{
NodeName: utilpointer.StringPtr("node-2"),
},
},
},
expectedEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: utilpointer.StringPtr("node-1"),
},
{
NodeName: utilpointer.StringPtr("node-2"),
},
},
},
},
{
name: "node name gate disabled, field should be allowed",
nodeNameGateEnabled: false,
eps: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: utilpointer.StringPtr("node-1"),
},
{
NodeName: utilpointer.StringPtr("node-2"),
},
},
},
expectedEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: nil,
},
{
NodeName: nil,
},
},
},
},
} }
for _, testcase := range testcases { for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) { t.Run(testcase.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testcase.terminatingGateEnabled)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testcase.terminatingGateEnabled)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceNodeName, testcase.nodeNameGateEnabled)()
dropDisabledConditionsOnCreate(testcase.eps) dropDisabledFieldsOnCreate(testcase.eps)
if !apiequality.Semantic.DeepEqual(testcase.eps, testcase.expectedEPS) { if !apiequality.Semantic.DeepEqual(testcase.eps, testcase.expectedEPS) {
t.Logf("actual endpointslice: %v", testcase.eps) t.Logf("actual endpointslice: %v", testcase.eps)
t.Logf("expected endpointslice: %v", testcase.expectedEPS) t.Logf("expected endpointslice: %v", testcase.expectedEPS)
@ -146,16 +196,17 @@ func Test_dropConditionsOnCreate(t *testing.T) {
} }
} }
func Test_dropTerminatingConditionOnUpdate(t *testing.T) { func Test_dropDisabledFieldsOnUpdate(t *testing.T) {
testcases := []struct { testcases := []struct {
name string name string
terminatingGateEnabled bool terminatingGateEnabled bool
nodeNameGateEnabled bool
oldEPS *discovery.EndpointSlice oldEPS *discovery.EndpointSlice
newEPS *discovery.EndpointSlice newEPS *discovery.EndpointSlice
expectedEPS *discovery.EndpointSlice expectedEPS *discovery.EndpointSlice
}{ }{
{ {
name: "gate enabled, field should be allowed", name: "terminating gate enabled, field should be allowed",
terminatingGateEnabled: true, terminatingGateEnabled: true,
oldEPS: &discovery.EndpointSlice{ oldEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{ Endpoints: []discovery.Endpoint{
@ -225,7 +276,7 @@ func Test_dropTerminatingConditionOnUpdate(t *testing.T) {
}, },
}, },
{ {
name: "gate disabled, and not set on existing EPS", name: "terminating gate disabled, and not set on existing EPS",
terminatingGateEnabled: false, terminatingGateEnabled: false,
oldEPS: &discovery.EndpointSlice{ oldEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{ Endpoints: []discovery.Endpoint{
@ -295,7 +346,7 @@ func Test_dropTerminatingConditionOnUpdate(t *testing.T) {
}, },
}, },
{ {
name: "gate disabled, and set on existing EPS", name: "terminating gate disabled, and set on existing EPS",
terminatingGateEnabled: false, terminatingGateEnabled: false,
oldEPS: &discovery.EndpointSlice{ oldEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{ Endpoints: []discovery.Endpoint{
@ -365,7 +416,7 @@ func Test_dropTerminatingConditionOnUpdate(t *testing.T) {
}, },
}, },
{ {
name: "gate disabled, and set on existing EPS with new values", name: "terminating gate disabled, and set on existing EPS with new values",
terminatingGateEnabled: false, terminatingGateEnabled: false,
oldEPS: &discovery.EndpointSlice{ oldEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{ Endpoints: []discovery.Endpoint{
@ -431,13 +482,116 @@ func Test_dropTerminatingConditionOnUpdate(t *testing.T) {
}, },
}, },
}, },
{
name: "node name gate enabled, set on new EPS",
nodeNameGateEnabled: true,
oldEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: nil,
},
{
NodeName: nil,
},
},
},
newEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: utilpointer.StringPtr("node-1"),
},
{
NodeName: utilpointer.StringPtr("node-2"),
},
},
},
expectedEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: utilpointer.StringPtr("node-1"),
},
{
NodeName: utilpointer.StringPtr("node-2"),
},
},
},
},
{
name: "node name gate disabled, set on new EPS",
nodeNameGateEnabled: false,
oldEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: nil,
},
{
NodeName: nil,
},
},
},
newEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: utilpointer.StringPtr("node-1"),
},
{
NodeName: utilpointer.StringPtr("node-2"),
},
},
},
expectedEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: nil,
},
{
NodeName: nil,
},
},
},
},
{
name: "node name gate disabled, set on old and updated EPS",
nodeNameGateEnabled: false,
oldEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: utilpointer.StringPtr("node-1-old"),
},
{
NodeName: utilpointer.StringPtr("node-2-old"),
},
},
},
newEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: utilpointer.StringPtr("node-1"),
},
{
NodeName: utilpointer.StringPtr("node-2"),
},
},
},
expectedEPS: &discovery.EndpointSlice{
Endpoints: []discovery.Endpoint{
{
NodeName: utilpointer.StringPtr("node-1"),
},
{
NodeName: utilpointer.StringPtr("node-2"),
},
},
},
},
} }
for _, testcase := range testcases { for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) { t.Run(testcase.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testcase.terminatingGateEnabled)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceTerminatingCondition, testcase.terminatingGateEnabled)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EndpointSliceNodeName, testcase.nodeNameGateEnabled)()
dropDisabledConditionsOnUpdate(testcase.oldEPS, testcase.newEPS) dropDisabledFieldsOnUpdate(testcase.oldEPS, testcase.newEPS)
if !apiequality.Semantic.DeepEqual(testcase.newEPS, testcase.expectedEPS) { if !apiequality.Semantic.DeepEqual(testcase.newEPS, testcase.expectedEPS) {
t.Logf("actual endpointslice: %v", testcase.newEPS) t.Logf("actual endpointslice: %v", testcase.newEPS)
t.Logf("expected endpointslice: %v", testcase.expectedEPS) t.Logf("expected endpointslice: %v", testcase.expectedEPS)