Merge pull request #3241 from XiShanYongYe-Chang/add-generation-id-for-cluster
Increase `.metadata.generation` once desired state of the `Cluster` object is changed.
This commit is contained in:
commit
83c7862289
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
@ -73,6 +74,10 @@ func (Strategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
|||
// PrepareForCreate is invoked on create before validation to normalize the object.
|
||||
func (Strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
cluster := obj.(*clusterapis.Cluster)
|
||||
cluster.Status = clusterapis.ClusterStatus{}
|
||||
|
||||
cluster.Generation = 1
|
||||
|
||||
if utilfeature.DefaultMutableFeatureGate.Enabled(features.CustomizedClusterResourceModeling) {
|
||||
if len(cluster.Spec.ResourceModels) == 0 {
|
||||
mutation.SetDefaultClusterResourceModels(cluster)
|
||||
|
@ -84,10 +89,18 @@ func (Strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
|||
|
||||
// PrepareForUpdate is invoked on update before validation to normalize the object.
|
||||
func (Strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
cluster := obj.(*clusterapis.Cluster)
|
||||
newCluster := obj.(*clusterapis.Cluster)
|
||||
oldCluster := old.(*clusterapis.Cluster)
|
||||
newCluster.Status = oldCluster.Status
|
||||
|
||||
// Any changes to the spec increases the generation number.
|
||||
if !apiequality.Semantic.DeepEqual(newCluster.Spec, oldCluster.Spec) {
|
||||
newCluster.Generation = oldCluster.Generation + 1
|
||||
}
|
||||
|
||||
if utilfeature.DefaultMutableFeatureGate.Enabled(features.CustomizedClusterResourceModeling) {
|
||||
if len(cluster.Spec.ResourceModels) != 0 {
|
||||
mutation.StandardizeClusterResourceModels(cluster.Spec.ResourceModels)
|
||||
if len(newCluster.Spec.ResourceModels) != 0 {
|
||||
mutation.StandardizeClusterResourceModels(newCluster.Spec.ResourceModels)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,12 @@ func getValidCluster(name string) *clusterapis.Cluster {
|
|||
}
|
||||
}
|
||||
|
||||
func getValidClusterWithGeneration(name string, generation int64) *clusterapis.Cluster {
|
||||
cluster := getValidCluster(name)
|
||||
cluster.Generation = generation
|
||||
return cluster
|
||||
}
|
||||
|
||||
func setFeatureGateDuringTest(tb testing.TB, gate featuregate.FeatureGate, f featuregate.Feature, value bool) func() {
|
||||
originalValue := gate.Enabled(f)
|
||||
|
||||
|
@ -59,7 +65,7 @@ func TestStrategy_PrepareForCreate(t *testing.T) {
|
|||
clusterStrategy := NewStrategy(clusterscheme.Scheme)
|
||||
ctx := request.NewContext()
|
||||
|
||||
defaultResourceModelCluster := getValidCluster("m1")
|
||||
defaultResourceModelCluster := getValidClusterWithGeneration("m1", 1)
|
||||
mutation.SetDefaultClusterResourceModels(defaultResourceModelCluster)
|
||||
|
||||
standardResourceModelClusterBefore := getValidCluster("m2")
|
||||
|
@ -85,7 +91,7 @@ func TestStrategy_PrepareForCreate(t *testing.T) {
|
|||
},
|
||||
}}
|
||||
|
||||
standardResourceModelClusterAfter := getValidCluster("m2")
|
||||
standardResourceModelClusterAfter := getValidClusterWithGeneration("m2", 1)
|
||||
standardResourceModelClusterAfter.Spec.ResourceModels = []clusterapis.ResourceModel{
|
||||
{
|
||||
Grade: 1,
|
||||
|
@ -118,7 +124,7 @@ func TestStrategy_PrepareForCreate(t *testing.T) {
|
|||
{
|
||||
name: "featureGate CustomizedClusterResourceModeling is false",
|
||||
object: getValidCluster("cluster"),
|
||||
expect: getValidCluster("cluster"),
|
||||
expect: getValidClusterWithGeneration("cluster", 1),
|
||||
gateFlag: false,
|
||||
},
|
||||
{
|
||||
|
@ -152,7 +158,7 @@ func TestStrategy_PrepareForUpdate(t *testing.T) {
|
|||
clusterStrategy := NewStrategy(clusterscheme.Scheme)
|
||||
ctx := request.NewContext()
|
||||
|
||||
standardResourceModelClusterBefore := getValidCluster("m2")
|
||||
standardResourceModelClusterBefore := getValidClusterWithGeneration("m2", 2)
|
||||
standardResourceModelClusterBefore.Spec.ResourceModels = []clusterapis.ResourceModel{
|
||||
{
|
||||
Grade: 2,
|
||||
|
@ -175,7 +181,7 @@ func TestStrategy_PrepareForUpdate(t *testing.T) {
|
|||
},
|
||||
}}
|
||||
|
||||
standardResourceModelClusterAfter := getValidCluster("m2")
|
||||
standardResourceModelClusterAfter := getValidClusterWithGeneration("m2", 2)
|
||||
standardResourceModelClusterAfter.Spec.ResourceModels = []clusterapis.ResourceModel{
|
||||
{
|
||||
Grade: 1,
|
||||
|
@ -201,25 +207,51 @@ func TestStrategy_PrepareForUpdate(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
name string
|
||||
object runtime.Object
|
||||
oldObj runtime.Object
|
||||
newObj runtime.Object
|
||||
expect runtime.Object
|
||||
gateFlag bool
|
||||
}{
|
||||
{
|
||||
name: "cluster spec has no change",
|
||||
oldObj: getValidClusterWithGeneration("cluster", 2),
|
||||
newObj: getValidClusterWithGeneration("cluster", 2),
|
||||
expect: getValidClusterWithGeneration("cluster", 2),
|
||||
gateFlag: false,
|
||||
},
|
||||
{
|
||||
name: "cluster spec has changed",
|
||||
oldObj: getValidClusterWithGeneration("cluster", 2),
|
||||
newObj: func() *clusterapis.Cluster {
|
||||
cluster := getValidClusterWithGeneration("cluster", 2)
|
||||
cluster.Spec.Provider = "a"
|
||||
return cluster
|
||||
}(),
|
||||
expect: func() *clusterapis.Cluster {
|
||||
cluster := getValidClusterWithGeneration("cluster", 3)
|
||||
cluster.Spec.Provider = "a"
|
||||
return cluster
|
||||
}(),
|
||||
gateFlag: false,
|
||||
},
|
||||
{
|
||||
name: "featureGate CustomizedClusterResourceModeling is false",
|
||||
object: getValidCluster("cluster"),
|
||||
expect: getValidCluster("cluster"),
|
||||
oldObj: getValidClusterWithGeneration("cluster", 2),
|
||||
newObj: getValidClusterWithGeneration("cluster", 2),
|
||||
expect: getValidClusterWithGeneration("cluster", 2),
|
||||
gateFlag: false,
|
||||
},
|
||||
{
|
||||
name: "featureGate CustomizedClusterResourceModeling is true and cluster.Spec.ResourceModels is nil",
|
||||
object: getValidCluster("m1"),
|
||||
expect: getValidCluster("m1"),
|
||||
oldObj: getValidClusterWithGeneration("m1", 2),
|
||||
newObj: getValidClusterWithGeneration("m1", 2),
|
||||
expect: getValidClusterWithGeneration("m1", 2),
|
||||
gateFlag: true,
|
||||
},
|
||||
{
|
||||
name: "featureGate CustomizedClusterResourceModeling is true and cluster.Spec.ResourceModels is not nil",
|
||||
object: standardResourceModelClusterBefore,
|
||||
oldObj: standardResourceModelClusterBefore,
|
||||
newObj: standardResourceModelClusterBefore,
|
||||
expect: standardResourceModelClusterAfter,
|
||||
gateFlag: true,
|
||||
},
|
||||
|
@ -230,9 +262,9 @@ func TestStrategy_PrepareForUpdate(t *testing.T) {
|
|||
runtimeutil.Must(utilfeature.DefaultMutableFeatureGate.Add(features.DefaultFeatureGates))
|
||||
setFeatureGateDuringTest(t, utilfeature.DefaultMutableFeatureGate, features.CustomizedClusterResourceModeling, tt.gateFlag)
|
||||
|
||||
clusterStrategy.PrepareForUpdate(ctx, tt.object, nil)
|
||||
if !reflect.DeepEqual(tt.expect, tt.object) {
|
||||
t.Errorf("Object mismatch! Excepted: \n%#v \ngot: \n%#b", tt.expect, tt.object)
|
||||
clusterStrategy.PrepareForUpdate(ctx, tt.newObj, tt.oldObj)
|
||||
if !reflect.DeepEqual(tt.expect, tt.newObj) {
|
||||
t.Errorf("Object mismatch! Excepted: \n%#v \ngot: \n%#b", tt.expect, tt.newObj)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ func (s *Scheduler) updateCluster(oldObj, newObj interface{}) {
|
|||
switch {
|
||||
case !equality.Semantic.DeepEqual(oldCluster.Labels, newCluster.Labels):
|
||||
fallthrough
|
||||
case !equality.Semantic.DeepEqual(oldCluster.Spec, newCluster.Spec):
|
||||
case oldCluster.Generation != newCluster.Generation:
|
||||
s.enqueueAffectedBindings(oldCluster, newCluster)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue