mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-13 13:55:41 +00:00
Merge pull request #120398 from aleksandra-malinowska/sts-restart-always
Make StatefulSet restart pods with phase Succeeded
This commit is contained in:
commit
3eca0a5f78
@ -375,13 +375,27 @@ func (ssc *defaultStatefulSetControl) processReplica(
|
|||||||
replicas []*v1.Pod,
|
replicas []*v1.Pod,
|
||||||
i int) (bool, error) {
|
i int) (bool, error) {
|
||||||
logger := klog.FromContext(ctx)
|
logger := klog.FromContext(ctx)
|
||||||
// delete and recreate failed pods
|
// Delete and recreate pods which finished running.
|
||||||
if isFailed(replicas[i]) {
|
//
|
||||||
ssc.recorder.Eventf(set, v1.EventTypeWarning, "RecreatingFailedPod",
|
// Note that pods with phase Succeeded will also trigger this event. This is
|
||||||
"StatefulSet %s/%s is recreating failed Pod %s",
|
// because final pod phase of evicted or otherwise forcibly stopped pods
|
||||||
set.Namespace,
|
// (e.g. terminated on node reboot) is determined by the exit code of the
|
||||||
set.Name,
|
// container, not by the reason for pod termination. We should restart the pod
|
||||||
replicas[i].Name)
|
// regardless of the exit code.
|
||||||
|
if isFailed(replicas[i]) || isSucceeded(replicas[i]) {
|
||||||
|
if isFailed(replicas[i]) {
|
||||||
|
ssc.recorder.Eventf(set, v1.EventTypeWarning, "RecreatingFailedPod",
|
||||||
|
"StatefulSet %s/%s is recreating failed Pod %s",
|
||||||
|
set.Namespace,
|
||||||
|
set.Name,
|
||||||
|
replicas[i].Name)
|
||||||
|
} else {
|
||||||
|
ssc.recorder.Eventf(set, v1.EventTypeNormal, "RecreatingTerminatedPod",
|
||||||
|
"StatefulSet %s/%s is recreating terminated Pod %s",
|
||||||
|
set.Namespace,
|
||||||
|
set.Name,
|
||||||
|
replicas[i].Name)
|
||||||
|
}
|
||||||
if err := ssc.podControl.DeleteStatefulPod(set, replicas[i]); err != nil {
|
if err := ssc.podControl.DeleteStatefulPod(set, replicas[i]); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,7 @@ func TestStatefulSetControl(t *testing.T) {
|
|||||||
{ScalesDown, simpleSetFn},
|
{ScalesDown, simpleSetFn},
|
||||||
{ReplacesPods, largeSetFn},
|
{ReplacesPods, largeSetFn},
|
||||||
{RecreatesFailedPod, simpleSetFn},
|
{RecreatesFailedPod, simpleSetFn},
|
||||||
|
{RecreatesSucceededPod, simpleSetFn},
|
||||||
{CreatePodFailure, simpleSetFn},
|
{CreatePodFailure, simpleSetFn},
|
||||||
{UpdatePodFailure, simpleSetFn},
|
{UpdatePodFailure, simpleSetFn},
|
||||||
{UpdateSetStatusFailure, simpleSetFn},
|
{UpdateSetStatusFailure, simpleSetFn},
|
||||||
@ -435,6 +436,44 @@ func RecreatesFailedPod(t *testing.T, set *apps.StatefulSet, invariants invarian
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RecreatesSucceededPod(t *testing.T, set *apps.StatefulSet, invariants invariantFunc) {
|
||||||
|
client := fake.NewSimpleClientset()
|
||||||
|
om, _, ssc := setupController(client)
|
||||||
|
selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
pods, err := om.podsLister.Pods(set.Namespace).List(selector)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if _, err := ssc.UpdateStatefulSet(context.TODO(), set, pods); err != nil {
|
||||||
|
t.Errorf("Error updating StatefulSet %s", err)
|
||||||
|
}
|
||||||
|
if err := invariants(set, om); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
pods, err = om.podsLister.Pods(set.Namespace).List(selector)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
pods[0].Status.Phase = v1.PodSucceeded
|
||||||
|
_ = om.podsIndexer.Update(pods[0])
|
||||||
|
if _, err := ssc.UpdateStatefulSet(context.TODO(), set, pods); err != nil {
|
||||||
|
t.Errorf("Error updating StatefulSet %s", err)
|
||||||
|
}
|
||||||
|
if err := invariants(set, om); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
pods, err = om.podsLister.Pods(set.Namespace).List(selector)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if isCreated(pods[0]) {
|
||||||
|
t.Error("StatefulSet did not recreate succeeded Pod")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func CreatePodFailure(t *testing.T, set *apps.StatefulSet, invariants invariantFunc) {
|
func CreatePodFailure(t *testing.T, set *apps.StatefulSet, invariants invariantFunc) {
|
||||||
client := fake.NewSimpleClientset(set)
|
client := fake.NewSimpleClientset(set)
|
||||||
om, _, ssc := setupController(client)
|
om, _, ssc := setupController(client)
|
||||||
|
@ -426,6 +426,11 @@ func isFailed(pod *v1.Pod) bool {
|
|||||||
return pod.Status.Phase == v1.PodFailed
|
return pod.Status.Phase == v1.PodFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isSucceeded returns true if pod has a Phase of PodSucceeded
|
||||||
|
func isSucceeded(pod *v1.Pod) bool {
|
||||||
|
return pod.Status.Phase == v1.PodSucceeded
|
||||||
|
}
|
||||||
|
|
||||||
// isTerminating returns true if pod's DeletionTimestamp has been set
|
// isTerminating returns true if pod's DeletionTimestamp has been set
|
||||||
func isTerminating(pod *v1.Pod) bool {
|
func isTerminating(pod *v1.Pod) bool {
|
||||||
return pod.DeletionTimestamp != nil
|
return pod.DeletionTimestamp != nil
|
||||||
|
Loading…
Reference in New Issue
Block a user