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:
karmada-bot 2023-03-10 11:35:15 +08:00 committed by GitHub
commit 83c7862289
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 18 deletions

View File

@ -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)
}
}
}

View File

@ -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)
}
})
}

View File

@ -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)
}
}