@@ -41,6 +41,7 @@ import (
4141 "k8s.io/client-go/util/retry"
4242 "k8s.io/utils/ptr"
4343 appsv1alpha1 "kusionstack.io/kube-api/apps/v1alpha1"
44+ "kusionstack.io/kube-xset/features"
4445 "sigs.k8s.io/controller-runtime/pkg/client"
4546 "sigs.k8s.io/controller-runtime/pkg/envtest"
4647 logf "sigs.k8s.io/controller-runtime/pkg/log"
@@ -53,8 +54,6 @@ import (
5354 "kusionstack.io/kuperator/pkg/controllers/utils/poddecoration/strategy"
5455 "kusionstack.io/kuperator/pkg/controllers/utils/podopslifecycle"
5556 collasetutils "kusionstack.io/kuperator/pkg/controllers/xcollaset/utils"
56- "kusionstack.io/kuperator/pkg/features"
57- "kusionstack.io/kuperator/pkg/utils/feature"
5857 "kusionstack.io/kuperator/pkg/utils/inject"
5958)
6059
@@ -69,6 +68,109 @@ var (
6968)
7069
7170var _ = Describe ("collaset controller" , func () {
71+ It ("inplaceUpdate with only metadata changed" , func () {
72+ testcase := "test-inplace-update-with-only-metadata-changed"
73+ Expect (createNamespace (c , testcase )).Should (BeNil ())
74+
75+ cs := & appsv1alpha1.CollaSet {
76+ ObjectMeta : metav1.ObjectMeta {
77+ Namespace : testcase ,
78+ Name : "foo" ,
79+ },
80+ Spec : appsv1alpha1.CollaSetSpec {
81+ Replicas : int32Pointer (2 ),
82+ Selector : & metav1.LabelSelector {
83+ MatchLabels : map [string ]string {
84+ "app" : "foo" ,
85+ },
86+ },
87+ Template : corev1.PodTemplateSpec {
88+ ObjectMeta : metav1.ObjectMeta {
89+ Labels : map [string ]string {
90+ "app" : "foo" ,
91+ },
92+ },
93+ Spec : corev1.PodSpec {
94+ Containers : []corev1.Container {
95+ {
96+ Name : "foo" ,
97+ Image : "nginx:v1" ,
98+ },
99+ },
100+ },
101+ },
102+ UpdateStrategy : appsv1alpha1.UpdateStrategy {
103+ OperationDelaySeconds : int32Pointer (1 ),
104+ PodUpdatePolicy : appsv1alpha1 .CollaSetInPlaceIfPossiblePodUpdateStrategyType ,
105+ },
106+ },
107+ }
108+ Expect (c .Create (context .TODO (), cs )).Should (BeNil ())
109+
110+ podList := & corev1.PodList {}
111+ Eventually (func () bool {
112+ Expect (c .List (context .TODO (), podList , client .InNamespace (cs .Namespace ))).Should (BeNil ())
113+ return len (podList .Items ) == 2
114+ }, 5 * time .Second , 1 * time .Second ).Should (BeTrue ())
115+ Expect (c .Get (context .TODO (), types.NamespacedName {Namespace : cs .Namespace , Name : cs .Name }, cs )).Should (BeNil ())
116+ Expect (expectedStatusReplicas (c , cs , 0 , 0 , 0 , 2 , 2 , 0 , 0 , 0 )).Should (BeNil ())
117+
118+ observedGeneration := cs .Status .ObservedGeneration
119+ // update CollaSet template metadata
120+ Expect (updateCollaSetWithRetry (c , cs .Namespace , cs .Name , func (cls * appsv1alpha1.CollaSet ) bool {
121+ cls .Spec .Template .Annotations = map [string ]string {
122+ "test" : "v1" ,
123+ }
124+ return true
125+ })).Should (BeNil ())
126+ Eventually (func () bool {
127+ Expect (c .Get (context .TODO (), types.NamespacedName {Namespace : cs .Namespace , Name : cs .Name }, cs )).Should (BeNil ())
128+ return cs .Status .ObservedGeneration != observedGeneration
129+ }, 5 * time .Second , 1 * time .Second ).Should (BeTrue ())
130+
131+ // allow origin pod to update
132+ Expect (c .List (context .TODO (), podList , client .InNamespace (cs .Namespace ))).Should (BeNil ())
133+ for i := range podList .Items {
134+ pod := & podList .Items [i ]
135+ Expect (updatePodWithRetry (c , pod .Namespace , pod .Name , func (pod * corev1.Pod ) bool {
136+ labelOperate := fmt .Sprintf ("%s/%s" , appsv1alpha1 .PodOperateLabelPrefix , collasetutils .UpdateOpsLifecycleAdapter .GetID ())
137+ pod .Labels [labelOperate ] = fmt .Sprintf ("%d" , time .Now ().UnixNano ())
138+ return true
139+ })).Should (BeNil ())
140+ }
141+
142+ // waiting for update finished
143+ Eventually (func () error {
144+ return expectedStatusReplicas (c , cs , 0 , 0 , 0 , 2 , 2 , 2 , 0 , 0 )
145+ }, 10 * time .Second , 1 * time .Second ).Should (BeNil ())
146+
147+ // mock container status
148+ Expect (c .List (context .TODO (), podList , client .InNamespace (cs .Namespace ))).Should (BeNil ())
149+ for i := range podList .Items {
150+ Expect (updatePodStatusWithRetry (c , podList .Items [i ].Namespace , podList .Items [i ].Name , func (pod * corev1.Pod ) bool {
151+ pod .Status .ContainerStatuses = []corev1.ContainerStatus {
152+ {
153+ Name : "foo" ,
154+ ImageID : "nginx:v1" ,
155+ },
156+ }
157+ return true
158+ })).Should (BeNil ())
159+ }
160+
161+ // check pods update are finished
162+ Eventually (func () bool {
163+ Expect (c .List (context .TODO (), podList , client .InNamespace (cs .Namespace ))).Should (BeNil ())
164+ for i := range podList .Items {
165+ pod := & podList .Items [i ]
166+ if podopslifecycle .IsDuringOps (collasetutils .UpdateOpsLifecycleAdapter , pod ) {
167+ return false
168+ }
169+ }
170+ return true
171+ }, 10 * time .Second , 1 * time .Second ).Should (BeTrue ())
172+ })
173+
72174 It ("replace pod with update" , func () {
73175 for _ , updateStrategy := range []appsv1alpha1.PodUpdateStrategyType {appsv1alpha1 .CollaSetRecreatePodUpdateStrategyType , appsv1alpha1 .CollaSetInPlaceIfPossiblePodUpdateStrategyType , appsv1alpha1 .CollaSetReplacePodUpdateStrategyType } {
74176 testcase := fmt .Sprintf ("test-replace-pod-with-%s-update" , strings .ToLower (string (updateStrategy )))
@@ -3665,7 +3767,7 @@ var _ = Describe("collaset controller", func() {
36653767 It ("podToDelete" , func () {
36663768 testcase := "test-pod-to-delete"
36673769 Expect (createNamespace (c , testcase )).Should (BeNil ())
3668- _ = feature .DefaultMutableFeatureGate .Set (fmt .Sprintf ("%s=%s" , features .ReclaimPodScaleStrategy , "true" ))
3770+ _ = features .DefaultMutableFeatureGate .Set (fmt .Sprintf ("%s=%s" , features .ReclaimScaleStrategy , "true" ))
36693771 cs := & appsv1alpha1.CollaSet {
36703772 ObjectMeta : metav1.ObjectMeta {
36713773 Namespace : testcase ,
@@ -3743,7 +3845,8 @@ var _ = Describe("collaset controller", func() {
37433845 It ("[podToDelete] scale" , func () {
37443846 testcase := "test-pod-to-delete-scale"
37453847 Expect (createNamespace (c , testcase )).Should (BeNil ())
3746- _ = feature .DefaultMutableFeatureGate .Set (fmt .Sprintf ("%s=%s" , features .ReclaimPodScaleStrategy , "true" ))
3848+
3849+ _ = features .DefaultMutableFeatureGate .Set (fmt .Sprintf ("%s=%s" , features .ReclaimScaleStrategy , "true" ))
37473850 cs := & appsv1alpha1.CollaSet {
37483851 ObjectMeta : metav1.ObjectMeta {
37493852 Namespace : testcase ,
@@ -3862,7 +3965,7 @@ var _ = Describe("collaset controller", func() {
38623965 It ("Exclude and Include pod" , func () {
38633966 testcase := "test-pod-to-exclude-include"
38643967 Expect (createNamespace (c , testcase )).Should (BeNil ())
3865- _ = feature .DefaultMutableFeatureGate .Set (fmt .Sprintf ("%s=%s" , features .ReclaimPodScaleStrategy , "true" ))
3968+ _ = features .DefaultMutableFeatureGate .Set (fmt .Sprintf ("%s=%s" , features .ReclaimScaleStrategy , "true" ))
38663969 cs := & appsv1alpha1.CollaSet {
38673970 ObjectMeta : metav1.ObjectMeta {
38683971 Namespace : testcase ,
@@ -4296,7 +4399,7 @@ var _ = Describe("collaset controller", func() {
42964399 It ("[Include] pod without revision" , func () {
42974400 testcase := "test-include-pod-without-revision"
42984401 Expect (createNamespace (c , testcase )).Should (BeNil ())
4299- _ = feature .DefaultMutableFeatureGate .Set (fmt .Sprintf ("%s=%s" , features .ReclaimPodScaleStrategy , "true" ))
4402+ _ = features .DefaultMutableFeatureGate .Set (fmt .Sprintf ("%s=%s" , features .ReclaimScaleStrategy , "true" ))
43004403 cs := & appsv1alpha1.CollaSet {
43014404 ObjectMeta : metav1.ObjectMeta {
43024405 Namespace : testcase ,
0 commit comments