Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scale and Update Parall with revert partition #219

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
42d1962
force scale and update parall
ColdsteelRail May 23, 2024
a448d11
scale out and update parallel
ColdsteelRail May 24, 2024
0cde4e7
update ut
ColdsteelRail May 24, 2024
8bdf57f
scale failed and update
ColdsteelRail May 27, 2024
475c320
fix:concurrent map write
ColdsteelRail May 28, 2024
4d9a24d
rephrase ut
ColdsteelRail May 29, 2024
41d81b0
add replace pair info to resourceContext
ColdsteelRail Jun 4, 2024
84774f0
add replace pair info to resourceContext2
ColdsteelRail Jun 4, 2024
7a54a56
fileter out scaleOutFailedAndUpdatedReplicas when deciding partition
ColdsteelRail Jun 4, 2024
75f5d80
add revision to ID if create pod succeeded, delete revision from ID i…
ColdsteelRail Jun 4, 2024
c7d63f4
revert partition
ColdsteelRail Jun 9, 2024
a59eebf
do not scale in updated pods first
ColdsteelRail Jun 11, 2024
a915611
utils errors ut
ColdsteelRail Jun 11, 2024
9f6b1b2
decideScalingOutNotUpdatedPods
ColdsteelRail Jun 11, 2024
e512fd8
revert needAllocateReplicas
ColdsteelRail Jun 12, 2024
9cad31c
add todo
ColdsteelRail Jun 12, 2024
4074381
add todo
ColdsteelRail Jun 12, 2024
75d2e66
decideContextRevision
ColdsteelRail Jun 13, 2024
0239c1b
needAllocateReplicas
ColdsteelRail Jun 13, 2024
a9862ba
decideNeedUpdateButNotCreate
ColdsteelRail Jun 13, 2024
afef13f
delete PodJustCreateContextDataKey if pod is replace new pod
ColdsteelRail Jun 13, 2024
1a0c7bb
decideNeedUpdateButNotCreate
ColdsteelRail Jun 13, 2024
61e1723
update decideContextRevision
ColdsteelRail Jun 13, 2024
8bb068d
update context only is neccessary
ColdsteelRail Jun 17, 2024
aab32b5
only mark podContext PodRecreateUpgrade if upgrade by recreate
ColdsteelRail Jun 18, 2024
e4df75b
construct placeholder for all IDs
ColdsteelRail Jun 19, 2024
3d3c2d1
hide onlyPlaceHolderPods if neccessary
ColdsteelRail Jun 19, 2024
b770d36
reset CollectPodInstanceID
ColdsteelRail Jun 19, 2024
44b3520
remove redundant funcs
ColdsteelRail Jun 19, 2024
931031d
make codes more clear
ColdsteelRail Jun 19, 2024
5f261d8
rephrase code
ColdsteelRail Jun 19, 2024
d3ff3ee
filterReplacingNewCreatedPod: filter out onlyPlaceHolders replace pods
ColdsteelRail Jun 19, 2024
480dafc
rename OnlyPlaceholder
ColdsteelRail Jun 19, 2024
3ee9da2
filter out onlyPlaceHolder origin pods in update
ColdsteelRail Jun 25, 2024
230d6d5
reuse new pod resourcecontext if possible;
ColdsteelRail Jul 1, 2024
cdde053
remove redundant println
ColdsteelRail Jul 1, 2024
6435914
fix reuse podContext ID
ColdsteelRail Jul 1, 2024
d5fea8f
fix reuse podContext ID
ColdsteelRail Jul 1, 2024
ec7a5e5
refactor classifyReplacingPodContexts
ColdsteelRail Jul 2, 2024
325122f
rename needDeletePodsIDs
ColdsteelRail Jul 2, 2024
9bbafcc
move codes to replace
ColdsteelRail Jul 2, 2024
43c20c2
error.go ut coverage
ColdsteelRail Jul 3, 2024
43669de
rename PlaceHolder
ColdsteelRail Jul 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions pkg/controllers/collaset/collaset_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,16 +228,13 @@ func (r *CollaSetReconciler) doSync(
return podWrappers, nil, err
}

scaling, scaleRequeueAfter, err := r.syncControl.Scale(ctx, instance, resources, podWrappers, ownedIDs)
if err != nil || scaling {
return podWrappers, scaleRequeueAfter, err
}
_, scaleRequeueAfter, scaleErr := r.syncControl.Scale(ctx, instance, resources, podWrappers, ownedIDs)
_, updateRequeueAfter, updateErr := r.syncControl.Update(ctx, instance, resources, podWrappers, ownedIDs)

_, updateRequeueAfter, err := r.syncControl.Update(ctx, instance, resources, podWrappers, ownedIDs)
err = controllerutils.AggregateErrors([]error{scaleErr, updateErr})
if updateRequeueAfter != nil && (scaleRequeueAfter == nil || *updateRequeueAfter < *scaleRequeueAfter) {
return podWrappers, updateRequeueAfter, err
}

return podWrappers, scaleRequeueAfter, err
}

Expand All @@ -254,7 +251,8 @@ func calculateStatus(
var scheduledReplicas, readyReplicas, availableReplicas, replicas, updatedReplicas, operatingReplicas,
updatedReadyReplicas, updatedAvailableReplicas int32

for _, podWrapper := range podWrappers {
activePods := synccontrol.FilterOutPlaceHolderPodWrappers(podWrappers)
for _, podWrapper := range activePods {
replicas++

isUpdated := false
Expand Down
229 changes: 228 additions & 1 deletion pkg/controllers/collaset/collaset_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,233 @@ var _ = Describe("collaset controller", func() {
}
})

It("scale succeed and update parallel", func() {
testcase := "test-scale-and-update"
Expect(createNamespace(c, testcase)).Should(BeNil())

cs := &appsv1alpha1.CollaSet{
ObjectMeta: metav1.ObjectMeta{
Namespace: testcase,
Name: "foo",
},
Spec: appsv1alpha1.CollaSetSpec{
Replicas: int32Pointer(2),
UpdateStrategy: appsv1alpha1.UpdateStrategy{
RollingUpdate: &appsv1alpha1.RollingUpdateCollaSetStrategy{
ByPartition: &appsv1alpha1.ByPartition{
Partition: int32Pointer(1),
},
},
},
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "foo",
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "foo",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "foo",
Image: "nginx:v1",
},
},
},
},
},
}

Expect(c.Create(context.TODO(), cs)).Should(BeNil())

podList := &corev1.PodList{}
Eventually(func() bool {
Expect(c.List(context.TODO(), podList, client.InNamespace(cs.Namespace))).Should(BeNil())
return len(podList.Items) == 2
}, 5*time.Second, 1*time.Second).Should(BeTrue())
Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: cs.Namespace, Name: cs.Name}, cs)).Should(BeNil())
Expect(expectedStatusReplicas(c, cs, 0, 0, 0, 2, 2, 0, 0, 0)).Should(BeNil())

// update and scale out to 3 replicas
Expect(updateCollaSetWithRetry(c, cs.Namespace, cs.Name, func(cls *appsv1alpha1.CollaSet) bool {
cls.Spec.Replicas = int32Pointer(3)
cls.Spec.Template.Spec.Containers[0].Image = "nginx:v2"
return true
})).Should(BeNil())

Eventually(func() int {
Expect(c.List(context.TODO(), podList, client.InNamespace(cs.Namespace))).Should(BeNil())
return len(podList.Items)
}, 5*time.Second, 1*time.Second).Should(BeEquivalentTo(3))

// allow Pod to do update
for i := range podList.Items {
pod := &podList.Items[i]
if !podopslifecycle.IsDuringOps(collasetutils.UpdateOpsLifecycleAdapter, pod) {
continue
}
if _, allowed := podopslifecycle.AllowOps(collasetutils.UpdateOpsLifecycleAdapter, 0, pod); allowed {
continue
}
Expect(updatePodWithRetry(c, pod.Namespace, pod.Name, func(pod *corev1.Pod) bool {
labelOperate := fmt.Sprintf("%s/%s", appsv1alpha1.PodOperateLabelPrefix, collasetutils.UpdateOpsLifecycleAdapter.GetID())
pod.Labels[labelOperate] = fmt.Sprintf("%d", time.Now().UnixNano())
return true
})).Should(BeNil())
}
Eventually(func() error {
return expectedStatusReplicas(c, cs, 0, 0, 0, 3, 2, 1, 0, 0)
}, 10*time.Second, 1*time.Second).Should(BeNil())

// delete updated pods to trigger scale out
Expect(c.List(context.TODO(), podList, client.InNamespace(cs.Namespace))).Should(BeNil())
for _, pod := range podList.Items {
if pod.Labels[appsv1.ControllerRevisionHashLabelKey] == cs.Status.UpdatedRevision {
Expect(c.Delete(ctx, &pod)).Should(BeNil())
}
}

Eventually(func() error {
return expectedStatusReplicas(c, cs, 0, 0, 0, 3, 2, 0, 0, 0)
}, 10*time.Second, 1*time.Second).Should(BeNil())

})

It("scale failed and update parallel", func() {
testcase := "test-scale-failed-and-update"
Expect(createNamespace(c, testcase)).Should(BeNil())

cs := &appsv1alpha1.CollaSet{
ObjectMeta: metav1.ObjectMeta{
Namespace: testcase,
Name: "foo",
},
Spec: appsv1alpha1.CollaSetSpec{
Replicas: int32Pointer(3),
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "foo",
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "foo",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "foo",
Image: "nginx:v1",
},
},
},
},
},
}

Expect(c.Create(context.TODO(), cs)).Should(BeNil())

podList := &corev1.PodList{}
Eventually(func() int {
Expect(c.List(context.TODO(), podList, client.InNamespace(cs.Namespace))).Should(BeNil())
return len(podList.Items)
}, 5*time.Second, 1*time.Second).Should(BeEquivalentTo(3))
Expect(expectedStatusReplicas(c, cs, 0, 0, 0, 3, 3, 0, 0, 0)).Should(BeNil())

// update collaset with non-exist pvc by partition=1
Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: cs.Namespace, Name: cs.Name}, cs)).Should(BeNil())
Expect(updateCollaSetWithRetry(c, cs.Namespace, cs.Name, func(cls *appsv1alpha1.CollaSet) bool {
cls.Spec.UpdateStrategy.RollingUpdate = &appsv1alpha1.RollingUpdateCollaSetStrategy{
ByPartition: &appsv1alpha1.ByPartition{
Partition: int32Pointer(1),
},
}
cls.Spec.Template.Spec.Containers = []corev1.Container{
{
Name: "foo",
Image: "nginx:v1",
VolumeMounts: []corev1.VolumeMount{
{
Name: "not-exist",
MountPath: "/tmp/not-exist",
},
},
},
}
return true
})).Should(BeNil())
// allow Pod to do update
Eventually(func() int32 {
Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: cs.Namespace, Name: cs.Name}, cs)).Should(BeNil())
return cs.Status.OperatingReplicas
}, 10*time.Second, 1*time.Second).Should(BeEquivalentTo(2))
Expect(c.List(context.TODO(), podList, client.InNamespace(cs.Namespace))).Should(BeNil())
for i := range podList.Items {
pod := &podList.Items[i]
if !podopslifecycle.IsDuringOps(collasetutils.UpdateOpsLifecycleAdapter, pod) {
continue
}
if _, allowed := podopslifecycle.AllowOps(collasetutils.UpdateOpsLifecycleAdapter, 0, pod); allowed {
continue
}
Expect(updatePodWithRetry(c, pod.Namespace, pod.Name, func(pod *corev1.Pod) bool {
labelOperate := fmt.Sprintf("%s/%s", appsv1alpha1.PodOperateLabelPrefix, collasetutils.UpdateOpsLifecycleAdapter.GetID())
pod.Labels[labelOperate] = fmt.Sprintf("%d", time.Now().UnixNano())
return true
})).Should(BeNil())
}
// scaling out failed with non-exist pvc
Eventually(func() int {
Expect(c.List(context.TODO(), podList, client.InNamespace(cs.Namespace))).Should(BeNil())
return len(podList.Items)
}, 10*time.Second, 1*time.Second).Should(BeEquivalentTo(1))
Expect(expectedStatusReplicas(c, cs, 0, 0, 0, 1, 0, 0, 0, 0)).Should(BeNil())

// update cls with good pod template
Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: cs.Namespace, Name: cs.Name}, cs)).Should(BeNil())
// allow Pod to do update
Expect(c.List(context.TODO(), podList, client.InNamespace(cs.Namespace))).Should(BeNil())
for i := range podList.Items {
pod := &podList.Items[i]
if !podopslifecycle.IsDuringOps(collasetutils.UpdateOpsLifecycleAdapter, pod) {
continue
}
if _, allowed := podopslifecycle.AllowOps(collasetutils.UpdateOpsLifecycleAdapter, 0, pod); allowed {
continue
}
Expect(updatePodWithRetry(c, pod.Namespace, pod.Name, func(pod *corev1.Pod) bool {
labelOperate := fmt.Sprintf("%s/%s", appsv1alpha1.PodOperateLabelPrefix, collasetutils.UpdateOpsLifecycleAdapter.GetID())
pod.Labels[labelOperate] = fmt.Sprintf("%d", time.Now().UnixNano())
return true
})).Should(BeNil())
}
Expect(updateCollaSetWithRetry(c, cs.Namespace, cs.Name, func(cls *appsv1alpha1.CollaSet) bool {
cls.Spec.UpdateStrategy.RollingUpdate = &appsv1alpha1.RollingUpdateCollaSetStrategy{
ByPartition: &appsv1alpha1.ByPartition{
Partition: int32Pointer(1),
},
}
cls.Spec.Template.Spec.Containers = []corev1.Container{
{
Name: "foo",
Image: "nginx:v1",
},
}
return true
})).Should(BeNil())
Eventually(func() int {
Expect(c.List(context.TODO(), podList, client.InNamespace(cs.Namespace))).Should(BeNil())
return len(podList.Items)
}, 5*time.Second, 1*time.Second).Should(BeEquivalentTo(3))
Expect(expectedStatusReplicas(c, cs, 0, 0, 0, 3, 3, 0, 0, 0)).Should(BeNil())
})

It("update pod policy", func() {
testcase := "test-update-pod-policy"
Expect(createNamespace(c, testcase)).Should(BeNil())
Expand Down Expand Up @@ -1442,7 +1669,7 @@ var _ = Describe("collaset controller", func() {
}, 5*time.Second, 1*time.Second).Should(BeTrue())
Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: cs.Namespace, Name: cs.Name}, cs)).Should(BeNil())
Expect(expectedStatusReplicas(c, cs, 0, 0, 0, 3, 3, 0, 0, 0)).Should(BeNil())
for _, partition := range []int32{0, 1, 2, 3} {
for _, partition := range []int32{3, 2, 1, 0} {
Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: cs.Namespace, Name: cs.Name}, cs)).Should(BeNil())
Expect(updateCollaSetWithRetry(c, cs.Namespace, cs.Name, func(cls *appsv1alpha1.CollaSet) bool {
cls.Spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{
Expand Down
14 changes: 9 additions & 5 deletions pkg/controllers/collaset/podcontext/podcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ import (
)

const (
OwnerContextKey = "Owner"
RevisionContextDataKey = "Revision"
PodDecorationRevisionKey = "PodDecorationRevisions"
OwnerContextKey = "Owner"
RevisionContextDataKey = "Revision"
PodDecorationRevisionKey = "PodDecorationRevisions"
JustCreateContextDataKey = "PodJustCreate"
RecreateUpdateContextDataKey = "PodRecreateUpdate"
)

func AllocateID(c client.Client, instance *appsv1alpha1.CollaSet, defaultRevision string, replicas int) (map[int]*appsv1alpha1.ContextDetail, error) {
Expand Down Expand Up @@ -84,9 +86,11 @@ func AllocateID(c client.Client, instance *appsv1alpha1.CollaSet, defaultRevisio

detail := &appsv1alpha1.ContextDetail{
ID: candidateID,
// TODO choose just create pods' revision according to scaleStrategy
Data: map[string]string{
OwnerContextKey: instance.Name,
RevisionContextDataKey: defaultRevision,
OwnerContextKey: instance.Name,
RevisionContextDataKey: defaultRevision,
JustCreateContextDataKey: "true",
},
}
existingIDs[candidateID] = detail
Expand Down
Loading
Loading