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"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
"k8s.io/apimachinery/pkg/fields"
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"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.
|
// PrepareForCreate is invoked on create before validation to normalize the object.
|
||||||
func (Strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (Strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
cluster := obj.(*clusterapis.Cluster)
|
cluster := obj.(*clusterapis.Cluster)
|
||||||
|
cluster.Status = clusterapis.ClusterStatus{}
|
||||||
|
|
||||||
|
cluster.Generation = 1
|
||||||
|
|
||||||
if utilfeature.DefaultMutableFeatureGate.Enabled(features.CustomizedClusterResourceModeling) {
|
if utilfeature.DefaultMutableFeatureGate.Enabled(features.CustomizedClusterResourceModeling) {
|
||||||
if len(cluster.Spec.ResourceModels) == 0 {
|
if len(cluster.Spec.ResourceModels) == 0 {
|
||||||
mutation.SetDefaultClusterResourceModels(cluster)
|
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.
|
// PrepareForUpdate is invoked on update before validation to normalize the object.
|
||||||
func (Strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.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 utilfeature.DefaultMutableFeatureGate.Enabled(features.CustomizedClusterResourceModeling) {
|
||||||
if len(cluster.Spec.ResourceModels) != 0 {
|
if len(newCluster.Spec.ResourceModels) != 0 {
|
||||||
mutation.StandardizeClusterResourceModels(cluster.Spec.ResourceModels)
|
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() {
|
func setFeatureGateDuringTest(tb testing.TB, gate featuregate.FeatureGate, f featuregate.Feature, value bool) func() {
|
||||||
originalValue := gate.Enabled(f)
|
originalValue := gate.Enabled(f)
|
||||||
|
|
||||||
|
@ -59,7 +65,7 @@ func TestStrategy_PrepareForCreate(t *testing.T) {
|
||||||
clusterStrategy := NewStrategy(clusterscheme.Scheme)
|
clusterStrategy := NewStrategy(clusterscheme.Scheme)
|
||||||
ctx := request.NewContext()
|
ctx := request.NewContext()
|
||||||
|
|
||||||
defaultResourceModelCluster := getValidCluster("m1")
|
defaultResourceModelCluster := getValidClusterWithGeneration("m1", 1)
|
||||||
mutation.SetDefaultClusterResourceModels(defaultResourceModelCluster)
|
mutation.SetDefaultClusterResourceModels(defaultResourceModelCluster)
|
||||||
|
|
||||||
standardResourceModelClusterBefore := getValidCluster("m2")
|
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{
|
standardResourceModelClusterAfter.Spec.ResourceModels = []clusterapis.ResourceModel{
|
||||||
{
|
{
|
||||||
Grade: 1,
|
Grade: 1,
|
||||||
|
@ -118,7 +124,7 @@ func TestStrategy_PrepareForCreate(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "featureGate CustomizedClusterResourceModeling is false",
|
name: "featureGate CustomizedClusterResourceModeling is false",
|
||||||
object: getValidCluster("cluster"),
|
object: getValidCluster("cluster"),
|
||||||
expect: getValidCluster("cluster"),
|
expect: getValidClusterWithGeneration("cluster", 1),
|
||||||
gateFlag: false,
|
gateFlag: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -152,7 +158,7 @@ func TestStrategy_PrepareForUpdate(t *testing.T) {
|
||||||
clusterStrategy := NewStrategy(clusterscheme.Scheme)
|
clusterStrategy := NewStrategy(clusterscheme.Scheme)
|
||||||
ctx := request.NewContext()
|
ctx := request.NewContext()
|
||||||
|
|
||||||
standardResourceModelClusterBefore := getValidCluster("m2")
|
standardResourceModelClusterBefore := getValidClusterWithGeneration("m2", 2)
|
||||||
standardResourceModelClusterBefore.Spec.ResourceModels = []clusterapis.ResourceModel{
|
standardResourceModelClusterBefore.Spec.ResourceModels = []clusterapis.ResourceModel{
|
||||||
{
|
{
|
||||||
Grade: 2,
|
Grade: 2,
|
||||||
|
@ -175,7 +181,7 @@ func TestStrategy_PrepareForUpdate(t *testing.T) {
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
standardResourceModelClusterAfter := getValidCluster("m2")
|
standardResourceModelClusterAfter := getValidClusterWithGeneration("m2", 2)
|
||||||
standardResourceModelClusterAfter.Spec.ResourceModels = []clusterapis.ResourceModel{
|
standardResourceModelClusterAfter.Spec.ResourceModels = []clusterapis.ResourceModel{
|
||||||
{
|
{
|
||||||
Grade: 1,
|
Grade: 1,
|
||||||
|
@ -201,25 +207,51 @@ func TestStrategy_PrepareForUpdate(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
object runtime.Object
|
oldObj runtime.Object
|
||||||
|
newObj runtime.Object
|
||||||
expect runtime.Object
|
expect runtime.Object
|
||||||
gateFlag bool
|
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",
|
name: "featureGate CustomizedClusterResourceModeling is false",
|
||||||
object: getValidCluster("cluster"),
|
oldObj: getValidClusterWithGeneration("cluster", 2),
|
||||||
expect: getValidCluster("cluster"),
|
newObj: getValidClusterWithGeneration("cluster", 2),
|
||||||
|
expect: getValidClusterWithGeneration("cluster", 2),
|
||||||
gateFlag: false,
|
gateFlag: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "featureGate CustomizedClusterResourceModeling is true and cluster.Spec.ResourceModels is nil",
|
name: "featureGate CustomizedClusterResourceModeling is true and cluster.Spec.ResourceModels is nil",
|
||||||
object: getValidCluster("m1"),
|
oldObj: getValidClusterWithGeneration("m1", 2),
|
||||||
expect: getValidCluster("m1"),
|
newObj: getValidClusterWithGeneration("m1", 2),
|
||||||
|
expect: getValidClusterWithGeneration("m1", 2),
|
||||||
gateFlag: true,
|
gateFlag: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "featureGate CustomizedClusterResourceModeling is true and cluster.Spec.ResourceModels is not nil",
|
name: "featureGate CustomizedClusterResourceModeling is true and cluster.Spec.ResourceModels is not nil",
|
||||||
object: standardResourceModelClusterBefore,
|
oldObj: standardResourceModelClusterBefore,
|
||||||
|
newObj: standardResourceModelClusterBefore,
|
||||||
expect: standardResourceModelClusterAfter,
|
expect: standardResourceModelClusterAfter,
|
||||||
gateFlag: true,
|
gateFlag: true,
|
||||||
},
|
},
|
||||||
|
@ -230,9 +262,9 @@ func TestStrategy_PrepareForUpdate(t *testing.T) {
|
||||||
runtimeutil.Must(utilfeature.DefaultMutableFeatureGate.Add(features.DefaultFeatureGates))
|
runtimeutil.Must(utilfeature.DefaultMutableFeatureGate.Add(features.DefaultFeatureGates))
|
||||||
setFeatureGateDuringTest(t, utilfeature.DefaultMutableFeatureGate, features.CustomizedClusterResourceModeling, tt.gateFlag)
|
setFeatureGateDuringTest(t, utilfeature.DefaultMutableFeatureGate, features.CustomizedClusterResourceModeling, tt.gateFlag)
|
||||||
|
|
||||||
clusterStrategy.PrepareForUpdate(ctx, tt.object, nil)
|
clusterStrategy.PrepareForUpdate(ctx, tt.newObj, tt.oldObj)
|
||||||
if !reflect.DeepEqual(tt.expect, tt.object) {
|
if !reflect.DeepEqual(tt.expect, tt.newObj) {
|
||||||
t.Errorf("Object mismatch! Excepted: \n%#v \ngot: \n%#b", tt.expect, tt.object)
|
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 {
|
switch {
|
||||||
case !equality.Semantic.DeepEqual(oldCluster.Labels, newCluster.Labels):
|
case !equality.Semantic.DeepEqual(oldCluster.Labels, newCluster.Labels):
|
||||||
fallthrough
|
fallthrough
|
||||||
case !equality.Semantic.DeepEqual(oldCluster.Spec, newCluster.Spec):
|
case oldCluster.Generation != newCluster.Generation:
|
||||||
s.enqueueAffectedBindings(oldCluster, newCluster)
|
s.enqueueAffectedBindings(oldCluster, newCluster)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue