mirror of
https://github.com/fluxcd/flagger.git
synced 2026-03-03 02:00:18 +00:00
pkg/canary/daemonset: fix ready condition according to kubectl
This commit is contained in:
@@ -44,21 +44,31 @@ func (c *DaemonSetController) IsCanaryReady(cd *flaggerv1.Canary) (bool, error)
|
||||
}
|
||||
|
||||
// isDaemonSetReady determines if a daemonset is ready by checking the number of old version daemons
|
||||
// reference: https://github.com/kubernetes/kubernetes/blob/5232ad4a00ec93942d0b2c6359ee6cd1201b46bc/pkg/kubectl/rollout_status.go#L110
|
||||
func (c *DaemonSetController) isDaemonSetReady(cd *flaggerv1.Canary, daemonSet *appsv1.DaemonSet) (bool, error) {
|
||||
if diff := daemonSet.Status.DesiredNumberScheduled - daemonSet.Status.UpdatedNumberScheduled; diff > 0 || daemonSet.Status.NumberUnavailable > 0 {
|
||||
if daemonSet.Generation <= daemonSet.Status.ObservedGeneration {
|
||||
// calculate conditions
|
||||
newCond := daemonSet.Status.UpdatedNumberScheduled < daemonSet.Status.DesiredNumberScheduled
|
||||
availableCond := daemonSet.Status.NumberAvailable < daemonSet.Status.DesiredNumberScheduled
|
||||
if !newCond && !availableCond {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// check if deadline exceeded
|
||||
from := cd.Status.LastTransitionTime
|
||||
delta := time.Duration(cd.GetProgressDeadlineSeconds()) * time.Second
|
||||
dl := from.Add(delta)
|
||||
if dl.Before(time.Now()) {
|
||||
if from.Add(delta).Before(time.Now()) {
|
||||
return false, fmt.Errorf("exceeded its progressDeadlineSeconds: %d", cd.GetProgressDeadlineSeconds())
|
||||
} else {
|
||||
return true, fmt.Errorf(
|
||||
"waiting for rollout to finish: desiredNumberScheduled=%d, updatedNumberScheduled=%d, numberUnavailable=%d",
|
||||
daemonSet.Status.DesiredNumberScheduled,
|
||||
daemonSet.Status.UpdatedNumberScheduled,
|
||||
daemonSet.Status.NumberUnavailable,
|
||||
)
|
||||
}
|
||||
|
||||
// retryable
|
||||
if newCond {
|
||||
return true, fmt.Errorf("waiting for rollout to finish: %d out of %d new pods have been updated",
|
||||
daemonSet.Status.UpdatedNumberScheduled, daemonSet.Status.DesiredNumberScheduled)
|
||||
} else if availableCond {
|
||||
return true, fmt.Errorf("waiting for rollout to finish: %d of %d updated pods are available",
|
||||
daemonSet.Status.NumberAvailable, daemonSet.Status.DesiredNumberScheduled)
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
return true, fmt.Errorf("waiting for rollout to finish: observed daemonset generation less then desired generation")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package canary
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -24,39 +25,57 @@ func TestDaemonSetController_IsReady(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDaemonSetController_isDaemonSetReady(t *testing.T) {
|
||||
ds := &appsv1.DaemonSet{
|
||||
Status: appsv1.DaemonSetStatus{
|
||||
DesiredNumberScheduled: 1,
|
||||
UpdatedNumberScheduled: 1,
|
||||
},
|
||||
}
|
||||
|
||||
cd := &flaggerv1.Canary{}
|
||||
cd.Spec.ProgressDeadlineSeconds = int32p(1e5)
|
||||
cd.Status.LastTransitionTime = metav1.Now()
|
||||
|
||||
// ready
|
||||
mocks := newDaemonSetFixture()
|
||||
_, err := mocks.controller.isDaemonSetReady(cd, ds)
|
||||
cd := &flaggerv1.Canary{}
|
||||
|
||||
// observed generation is less than desired generation
|
||||
ds := &appsv1.DaemonSet{Status: appsv1.DaemonSetStatus{}}
|
||||
ds.Status.ObservedGeneration--
|
||||
retyable, err := mocks.controller.isDaemonSetReady(cd, ds)
|
||||
require.Error(t, err)
|
||||
require.True(t, retyable)
|
||||
|
||||
// succeeded
|
||||
ds = &appsv1.DaemonSet{Status: appsv1.DaemonSetStatus{
|
||||
UpdatedNumberScheduled: 1,
|
||||
DesiredNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
}}
|
||||
retyable, err = mocks.controller.isDaemonSetReady(cd, ds)
|
||||
require.NoError(t, err)
|
||||
require.True(t, retyable)
|
||||
|
||||
// not ready but retriable
|
||||
ds.Status.NumberUnavailable++
|
||||
retrieable, err := mocks.controller.isDaemonSetReady(cd, ds)
|
||||
require.Error(t, err)
|
||||
require.True(t, retrieable)
|
||||
ds.Status.NumberUnavailable--
|
||||
|
||||
ds.Status.DesiredNumberScheduled++
|
||||
retrieable, err = mocks.controller.isDaemonSetReady(cd, ds)
|
||||
require.Error(t, err)
|
||||
require.True(t, retrieable)
|
||||
|
||||
// not ready and not retriable
|
||||
// deadline exceeded
|
||||
ds = &appsv1.DaemonSet{Status: appsv1.DaemonSetStatus{
|
||||
UpdatedNumberScheduled: 0,
|
||||
DesiredNumberScheduled: 1,
|
||||
}}
|
||||
cd.Status.LastTransitionTime = metav1.Now()
|
||||
cd.Spec.ProgressDeadlineSeconds = int32p(-1e5)
|
||||
retrieable, err = mocks.controller.isDaemonSetReady(cd, ds)
|
||||
cd.Spec.ProgressDeadlineSeconds = int32p(-1e6)
|
||||
retyable, err = mocks.controller.isDaemonSetReady(cd, ds)
|
||||
require.Error(t, err)
|
||||
require.False(t, retrieable)
|
||||
require.False(t, retyable)
|
||||
|
||||
// only newCond not satisfied
|
||||
ds = &appsv1.DaemonSet{Status: appsv1.DaemonSetStatus{
|
||||
UpdatedNumberScheduled: 0,
|
||||
DesiredNumberScheduled: 1,
|
||||
NumberAvailable: 1,
|
||||
}}
|
||||
cd.Spec.ProgressDeadlineSeconds = int32p(1e6)
|
||||
retyable, err = mocks.controller.isDaemonSetReady(cd, ds)
|
||||
require.Error(t, err)
|
||||
require.True(t, retyable)
|
||||
require.True(t, strings.Contains(err.Error(), "new pods"))
|
||||
|
||||
// only availableCond not satisfied
|
||||
ds = &appsv1.DaemonSet{Status: appsv1.DaemonSetStatus{
|
||||
UpdatedNumberScheduled: 1,
|
||||
DesiredNumberScheduled: 1,
|
||||
NumberAvailable: 0,
|
||||
}}
|
||||
retyable, err = mocks.controller.isDaemonSetReady(cd, ds)
|
||||
require.Error(t, err)
|
||||
require.True(t, retyable)
|
||||
require.True(t, strings.Contains(err.Error(), "available"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user