Skip to content

Commit c0d647a

Browse files
committed
kube-xset ok
1 parent 56492b4 commit c0d647a

File tree

12 files changed

+176
-109
lines changed

12 files changed

+176
-109
lines changed

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ require (
2323
k8s.io/kubernetes v0.0.0-00010101000000-000000000000
2424
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
2525
kusionstack.io/kube-api v0.7.4-0.20250909095208-496f60eea9b5
26-
kusionstack.io/kube-utils v0.2.1-0.20251031115408-8f00ba110277
26+
kusionstack.io/kube-utils v0.2.1-0.20251011035021-96222f41ab08
27+
kusionstack.io/kube-xset v0.0.0-20251111060928-069410a15229
2728
kusionstack.io/resourceconsist v0.0.1
2829
sigs.k8s.io/controller-runtime v0.17.3
2930
)

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,8 +1153,10 @@ k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6J
11531153
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
11541154
kusionstack.io/kube-api v0.7.4-0.20250909095208-496f60eea9b5 h1:/jbKYMeXiYnuxyJQs72MoL6vxVoY15FX/7tCKWljscY=
11551155
kusionstack.io/kube-api v0.7.4-0.20250909095208-496f60eea9b5/go.mod h1:e1jtrQH2LK5fD2nTyfIXG6nYrYbU8VXShRxTRwVPaLk=
1156-
kusionstack.io/kube-utils v0.2.1-0.20251031115408-8f00ba110277 h1:jsaRBLVOfkpAgPz1JA0Cp+fs7tqi+9Uccu0JJlCeaO0=
1157-
kusionstack.io/kube-utils v0.2.1-0.20251031115408-8f00ba110277/go.mod h1:KEHTfo1Y8SWMODnckF6daO2cSIW0FJ8fkk8PBA5O2GU=
1156+
kusionstack.io/kube-utils v0.2.1-0.20251011035021-96222f41ab08 h1:tH1muT0FVjaq6qTdNFzu7wbBJKo9gvYrc7Xl+1vJnUo=
1157+
kusionstack.io/kube-utils v0.2.1-0.20251011035021-96222f41ab08/go.mod h1:pThYvlUgm58SXyax5nxHRln6EW7l6sqkNmlUqa/6OR0=
1158+
kusionstack.io/kube-xset v0.0.0-20251111060928-069410a15229 h1:fTXG+HNxgM982pU/SnETY1fTRIcrrovs0Apn6h//zIo=
1159+
kusionstack.io/kube-xset v0.0.0-20251111060928-069410a15229/go.mod h1:FceKgqapMHhwiyIqCziTQRW27fsSXpPS611AApnyiYI=
11581160
kusionstack.io/resourceconsist v0.0.1 h1:+k/jriq5Ld7fQUYfWSMGynz/FesHtl3Rk2fmQPjBe0g=
11591161
kusionstack.io/resourceconsist v0.0.1/go.mod h1:816xS/fY6EOUbPFjXIWW/TGs8/YE46qP4ElKeIiwFdU=
11601162
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=

main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ import (
2222
"os"
2323
"path/filepath"
2424

25-
_ "k8s.io/client-go/plugin/pkg/client/auth"
26-
2725
"github.com/spf13/pflag"
2826
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2927
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
28+
_ "k8s.io/client-go/plugin/pkg/client/auth"
3029
"k8s.io/klog/v2"
3130
"k8s.io/klog/v2/klogr"
3231
appsv1alpha1 "kusionstack.io/kube-api/apps/v1alpha1"
32+
xsetfeatures "kusionstack.io/kube-xset/features"
3333
ctrl "sigs.k8s.io/controller-runtime"
3434
"sigs.k8s.io/controller-runtime/pkg/healthz"
3535

@@ -71,6 +71,7 @@ func main() {
7171
defer klog.Flush()
7272

7373
feature.DefaultMutableFeatureGate.AddFlag(pflag.CommandLine)
74+
xsetfeatures.DefaultMutableFeatureGate.AddFlag(pflag.CommandLine)
7475
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
7576
pflag.Parse()
7677

pkg/controllers/xcollaset/collaset_controller.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ import (
2424
corev1 "k8s.io/api/core/v1"
2525
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626
appsv1alpha1 "kusionstack.io/kube-api/apps/v1alpha1"
27-
"kusionstack.io/kube-utils/xset"
28-
xsetapi "kusionstack.io/kube-utils/xset/api"
29-
"kusionstack.io/kube-utils/xset/synccontrols"
27+
kubexset "kusionstack.io/kube-xset"
28+
xsetapi "kusionstack.io/kube-xset/api"
29+
"kusionstack.io/kube-xset/synccontrols"
3030
"sigs.k8s.io/controller-runtime/pkg/client"
3131
"sigs.k8s.io/controller-runtime/pkg/manager"
3232

@@ -43,7 +43,7 @@ const (
4343
func Add(mgr manager.Manager) error {
4444
xSetController := &CollaSetController{}
4545
synccontrols.RegisterInPlaceIfPossibleUpdater(&inPlaceIfPossibleUpdater{})
46-
return xset.SetUpWithManager(mgr, xSetController)
46+
return kubexset.SetUpWithManager(mgr, xSetController)
4747
}
4848

4949
var _ xsetapi.XSetController = &CollaSetController{}
@@ -297,6 +297,6 @@ func (l *LifecycleAdapterGetter) GetUpdateOpsLifecycleAdapter() xsetapi.Lifecycl
297297

298298
type GetLabelManagerAdapterGetter struct{}
299299

300-
func (g *GetLabelManagerAdapterGetter) GetLabelManagerAdapter() xsetapi.XSetLabelAnnotationManager {
301-
return NewXSetControllerLabelManager()
300+
func (g *GetLabelManagerAdapterGetter) GetLabelManagerAdapter() map[xsetapi.XSetLabelAnnotationEnum]string {
301+
return defaultXSetControllerLabelManager
302302
}

pkg/controllers/xcollaset/collaset_controller_test.go

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

7170
var _ = 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,

pkg/controllers/xcollaset/decoration_adapter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2424
"k8s.io/apimachinery/pkg/util/sets"
2525
appsv1alpha1 "kusionstack.io/kube-api/apps/v1alpha1"
26-
xsetapi "kusionstack.io/kube-utils/xset/api"
26+
xsetapi "kusionstack.io/kube-xset/api"
2727
"sigs.k8s.io/controller-runtime/pkg/client"
2828
"sigs.k8s.io/controller-runtime/pkg/controller"
2929
"sigs.k8s.io/controller-runtime/pkg/event"

pkg/controllers/xcollaset/lifecycle_adapter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package xcollaset
1818

1919
import (
2020
appsv1alpha1 "kusionstack.io/kube-api/apps/v1alpha1"
21-
xsetapi "kusionstack.io/kube-utils/xset/api"
21+
xsetapi "kusionstack.io/kube-xset/api"
2222
"sigs.k8s.io/controller-runtime/pkg/client"
2323

2424
"kusionstack.io/kuperator/pkg/controllers/utils/podopslifecycle"

pkg/controllers/xcollaset/pod_updater.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import (
2828
"k8s.io/apimachinery/pkg/util/sets"
2929
appsv1alpha1 "kusionstack.io/kube-api/apps/v1alpha1"
3030
clientutil "kusionstack.io/kube-utils/client"
31-
"kusionstack.io/kube-utils/xset/api"
32-
"kusionstack.io/kube-utils/xset/synccontrols"
31+
"kusionstack.io/kube-xset/api"
32+
"kusionstack.io/kube-xset/synccontrols"
3333
"sigs.k8s.io/controller-runtime/pkg/client"
3434

3535
"kusionstack.io/kuperator/pkg/controllers/xcollaset/utils"
@@ -95,10 +95,9 @@ func (u *inPlaceIfPossibleUpdater) FulfillTargetUpdatedInfo(ctx context.Context,
9595
return err
9696
}
9797

98+
var podStatus *PodStatus
9899
if targetUpdateInfo.OnlyMetadataChanged {
99-
if targetUpdateInfo.UpdatedTarget.GetAnnotations() != nil {
100-
delete(targetUpdateInfo.UpdatedTarget.GetAnnotations(), appsv1alpha1.LastPodStatusAnnotationKey)
101-
}
100+
podStatus = &PodStatus{ContainerStates: nil}
102101
} else {
103102
containerCurrentStatusMapping := map[string]*corev1.ContainerStatus{}
104103
currentPod := targetUpdateInfo.TargetWrapper.Object.(*corev1.Pod)
@@ -110,7 +109,7 @@ func (u *inPlaceIfPossibleUpdater) FulfillTargetUpdatedInfo(ctx context.Context,
110109
}
111110
}
112111

113-
podStatus := &PodStatus{ContainerStates: map[string]*ContainerStatus{}}
112+
podStatus = &PodStatus{ContainerStates: map[string]*ContainerStatus{}}
114113
updatedPod := targetUpdateInfo.UpdatedTarget.(*corev1.Pod)
115114
for _, container := range updatedPod.Spec.Containers {
116115
podStatus.ContainerStates[container.Name] = &ContainerStatus{
@@ -126,17 +125,18 @@ func (u *inPlaceIfPossibleUpdater) FulfillTargetUpdatedInfo(ctx context.Context,
126125
// store image ID of each container in current Pod
127126
podStatus.ContainerStates[container.Name].LastImageID = containerCurrentStatus.ImageID
128127
}
128+
}
129129

130-
podStatusStr, err := json.Marshal(podStatus)
131-
if err != nil {
132-
return err
133-
}
134-
135-
if targetUpdateInfo.UpdatedTarget.GetAnnotations() == nil {
136-
targetUpdateInfo.UpdatedTarget.SetAnnotations(map[string]string{})
137-
}
138-
targetUpdateInfo.UpdatedTarget.GetAnnotations()[appsv1alpha1.LastPodStatusAnnotationKey] = string(podStatusStr)
130+
podStatusStr, err := json.Marshal(podStatus)
131+
if err != nil {
132+
return err
133+
}
134+
anno := targetUpdateInfo.UpdatedTarget.GetAnnotations()
135+
if anno == nil {
136+
anno = make(map[string]string)
139137
}
138+
anno[appsv1alpha1.LastPodStatusAnnotationKey] = string(podStatusStr)
139+
targetUpdateInfo.UpdatedTarget.SetAnnotations(anno)
140140
return nil
141141
}
142142

@@ -198,7 +198,7 @@ func (u *inPlaceIfPossibleUpdater) UpgradeTarget(ctx context.Context, targetInfo
198198
}
199199

200200
func (u *inPlaceIfPossibleUpdater) GetTargetUpdateFinishStatus(_ context.Context, targetUpdateInfo *synccontrols.TargetUpdateInfo) (finished bool, msg string, err error) {
201-
if targetUpdateInfo.DecorationChanged {
201+
if !targetUpdateInfo.IsUpdatedRevision || targetUpdateInfo.DecorationChanged {
202202
return false, "add on not updated", nil
203203
}
204204

@@ -221,14 +221,14 @@ func (u *inPlaceIfPossibleUpdater) GetTargetUpdateFinishStatus(_ context.Context
221221

222222
targetLastState := &PodStatus{}
223223
if lastStateJson, exist := targetUpdateInfo.GetAnnotations()[appsv1alpha1.LastPodStatusAnnotationKey]; !exist {
224-
return false, "no target last state annotation", nil
224+
return false, "no pod last state annotation", nil
225225
} else if err := json.Unmarshal([]byte(lastStateJson), targetLastState); err != nil {
226226
msg := fmt.Sprintf("malformat target last state annotation [%s]: %s", lastStateJson, err.Error())
227227
return false, msg, errors.New(msg)
228228
}
229229

230230
if targetLastState.ContainerStates == nil {
231-
return true, "empty last container state recorded", nil
231+
return true, "pod updated with only metadata changed", nil
232232
}
233233

234234
imageMapping := map[string]string{}

pkg/controllers/xcollaset/pvc_adapter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package xcollaset
1919
import (
2020
corev1 "k8s.io/api/core/v1"
2121
appsv1alpha1 "kusionstack.io/kube-api/apps/v1alpha1"
22-
xsetapi "kusionstack.io/kube-utils/xset/api"
22+
xsetapi "kusionstack.io/kube-xset/api"
2323
"sigs.k8s.io/controller-runtime/pkg/client"
2424

2525
"kusionstack.io/kuperator/pkg/controllers/xcollaset/utils"

0 commit comments

Comments
 (0)