Speed up attach/detach controller integration tests

Internal attach/detach controller timers should be configurable and tests
should use much shorter values.

reconcilerSyncDuration is deliberately left out of TimerConfig because it's
the only one that's not a constant one, it's configurable by user.
pull/6/head
Jan Safranek 2017-06-16 12:15:04 +02:00
parent 6742fda0bb
commit b28790a63b
4 changed files with 45 additions and 22 deletions

View File

@ -166,7 +166,9 @@ func startAttachDetachController(ctx ControllerContext) (bool, error) {
ctx.Cloud, ctx.Cloud,
ProbeAttachableVolumePlugins(ctx.Options.VolumeConfiguration), ProbeAttachableVolumePlugins(ctx.Options.VolumeConfiguration),
ctx.Options.DisableAttachDetachReconcilerSync, ctx.Options.DisableAttachDetachReconcilerSync,
ctx.Options.ReconcilerSyncLoopPeriod.Duration) ctx.Options.ReconcilerSyncLoopPeriod.Duration,
attachdetach.DefaultTimerConfig,
)
if attachDetachControllerErr != nil { if attachDetachControllerErr != nil {
return true, fmt.Errorf("failed to start attach/detach controller: %v", attachDetachControllerErr) return true, fmt.Errorf("failed to start attach/detach controller: %v", attachDetachControllerErr)
} }

View File

@ -50,26 +50,38 @@ import (
"k8s.io/kubernetes/pkg/volume/util/volumehelper" "k8s.io/kubernetes/pkg/volume/util/volumehelper"
) )
const ( // TimerConfig contains configuration of internal attach/detach timers and
// loopPeriod is the amount of time the reconciler loop waits between // should be used only to speed up tests. DefaultTimerConfig is the suggested
// successive executions // timer configuration for production.
reconcilerLoopPeriod time.Duration = 100 * time.Millisecond type TimerConfig struct {
// ReconcilerLoopPeriod is the amount of time the reconciler loop waits
// between successive executions
ReconcilerLoopPeriod time.Duration
// reconcilerMaxWaitForUnmountDuration is the maximum amount of time the // ReconcilerMaxWaitForUnmountDuration is the maximum amount of time the
// attach detach controller will wait for a volume to be safely unmounted // attach detach controller will wait for a volume to be safely unmounted
// from its node. Once this time has expired, the controller will assume the // from its node. Once this time has expired, the controller will assume the
// node or kubelet are unresponsive and will detach the volume anyway. // node or kubelet are unresponsive and will detach the volume anyway.
reconcilerMaxWaitForUnmountDuration time.Duration = 6 * time.Minute ReconcilerMaxWaitForUnmountDuration time.Duration
// desiredStateOfWorldPopulatorLoopSleepPeriod is the amount of time the // DesiredStateOfWorldPopulatorLoopSleepPeriod is the amount of time the
// DesiredStateOfWorldPopulator loop waits between successive executions // DesiredStateOfWorldPopulator loop waits between successive executions
desiredStateOfWorldPopulatorLoopSleepPeriod time.Duration = 1 * time.Minute DesiredStateOfWorldPopulatorLoopSleepPeriod time.Duration
// desiredStateOfWorldPopulatorListPodsRetryDuration is the amount of // DesiredStateOfWorldPopulatorListPodsRetryDuration is the amount of
// time the DesiredStateOfWorldPopulator loop waits between list pods // time the DesiredStateOfWorldPopulator loop waits between list pods
// calls. // calls.
desiredStateOfWorldPopulatorListPodsRetryDuration time.Duration = 3 * time.Minute DesiredStateOfWorldPopulatorListPodsRetryDuration time.Duration
) }
// DefaultTimerConfig is the default configuration of Attach/Detach controller
// timers.
var DefaultTimerConfig TimerConfig = TimerConfig{
ReconcilerLoopPeriod: 100 * time.Millisecond,
ReconcilerMaxWaitForUnmountDuration: 6 * time.Minute,
DesiredStateOfWorldPopulatorLoopSleepPeriod: 1 * time.Minute,
DesiredStateOfWorldPopulatorListPodsRetryDuration: 3 * time.Minute,
}
// AttachDetachController defines the operations supported by this controller. // AttachDetachController defines the operations supported by this controller.
type AttachDetachController interface { type AttachDetachController interface {
@ -87,7 +99,8 @@ func NewAttachDetachController(
cloud cloudprovider.Interface, cloud cloudprovider.Interface,
plugins []volume.VolumePlugin, plugins []volume.VolumePlugin,
disableReconciliationSync bool, disableReconciliationSync bool,
reconcilerSyncDuration time.Duration) (AttachDetachController, error) { reconcilerSyncDuration time.Duration,
timerConfig TimerConfig) (AttachDetachController, error) {
// TODO: The default resyncPeriod for shared informers is 12 hours, this is // TODO: The default resyncPeriod for shared informers is 12 hours, this is
// unacceptable for the attach/detach controller. For example, if a pod is // unacceptable for the attach/detach controller. For example, if a pod is
// skipped because the node it is scheduled to didn't set its annotation in // skipped because the node it is scheduled to didn't set its annotation in
@ -137,8 +150,8 @@ func NewAttachDetachController(
// Default these to values in options // Default these to values in options
adc.reconciler = reconciler.NewReconciler( adc.reconciler = reconciler.NewReconciler(
reconcilerLoopPeriod, timerConfig.ReconcilerLoopPeriod,
reconcilerMaxWaitForUnmountDuration, timerConfig.ReconcilerMaxWaitForUnmountDuration,
reconcilerSyncDuration, reconcilerSyncDuration,
disableReconciliationSync, disableReconciliationSync,
adc.desiredStateOfWorld, adc.desiredStateOfWorld,
@ -148,8 +161,8 @@ func NewAttachDetachController(
recorder) recorder)
adc.desiredStateOfWorldPopulator = populator.NewDesiredStateOfWorldPopulator( adc.desiredStateOfWorldPopulator = populator.NewDesiredStateOfWorldPopulator(
desiredStateOfWorldPopulatorLoopSleepPeriod, timerConfig.DesiredStateOfWorldPopulatorLoopSleepPeriod,
desiredStateOfWorldPopulatorListPodsRetryDuration, timerConfig.DesiredStateOfWorldPopulatorListPodsRetryDuration,
podInformer.Lister(), podInformer.Lister(),
adc.desiredStateOfWorld, adc.desiredStateOfWorld,
&adc.volumePluginMgr, &adc.volumePluginMgr,

View File

@ -46,7 +46,8 @@ func Test_NewAttachDetachController_Positive(t *testing.T) {
nil, /* cloud */ nil, /* cloud */
nil, /* plugins */ nil, /* plugins */
false, false,
time.Second*5) 5*time.Second,
DefaultTimerConfig)
// Assert // Assert
if err != nil { if err != nil {
@ -212,7 +213,8 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2
nil, /* cloud */ nil, /* cloud */
plugins, plugins,
false, false,
time.Second*1) 1*time.Second,
DefaultTimerConfig)
if err != nil { if err != nil {
t.Fatalf("Run failed with error. Expected: <no error> Actual: <%v>", err) t.Fatalf("Run failed with error. Expected: <no error> Actual: <%v>", err)

View File

@ -82,7 +82,6 @@ func TestPodDeletionWithDswp(t *testing.T) {
_, server, closeFn := framework.RunAMaster(framework.NewIntegrationTestMasterConfig()) _, server, closeFn := framework.RunAMaster(framework.NewIntegrationTestMasterConfig())
defer closeFn() defer closeFn()
namespaceName := "test-pod-deletion" namespaceName := "test-pod-deletion"
node := &v1.Node{ node := &v1.Node{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "node-sandbox", Name: "node-sandbox",
@ -283,7 +282,7 @@ func TestPodUpdateWithKeepTerminatedPodVolumes(t *testing.T) {
// running the RC manager to prevent the rc manager from creating new pods // running the RC manager to prevent the rc manager from creating new pods
// rather than adopting the existing ones. // rather than adopting the existing ones.
func waitToObservePods(t *testing.T, podInformer cache.SharedIndexInformer, podNum int) { func waitToObservePods(t *testing.T, podInformer cache.SharedIndexInformer, podNum int) {
if err := wait.Poll(10*time.Second, 60*time.Second, func() (bool, error) { if err := wait.Poll(100*time.Millisecond, 60*time.Second, func() (bool, error) {
objects := podInformer.GetIndexer().List() objects := podInformer.GetIndexer().List()
if len(objects) == podNum { if len(objects) == podNum {
return true, nil return true, nil
@ -347,6 +346,12 @@ func createAdClients(ns *v1.Namespace, t *testing.T, server *httptest.Server, sy
plugins := []volume.VolumePlugin{plugin} plugins := []volume.VolumePlugin{plugin}
cloud := &fakecloud.FakeCloud{} cloud := &fakecloud.FakeCloud{}
informers := informers.NewSharedInformerFactory(testClient, resyncPeriod) informers := informers.NewSharedInformerFactory(testClient, resyncPeriod)
timers := attachdetach.TimerConfig{
ReconcilerLoopPeriod: 100 * time.Millisecond,
ReconcilerMaxWaitForUnmountDuration: 6 * time.Second,
DesiredStateOfWorldPopulatorLoopSleepPeriod: 1 * time.Second,
DesiredStateOfWorldPopulatorListPodsRetryDuration: 3 * time.Second,
}
ctrl, err := attachdetach.NewAttachDetachController( ctrl, err := attachdetach.NewAttachDetachController(
testClient, testClient,
informers.Core().V1().Pods(), informers.Core().V1().Pods(),
@ -356,7 +361,8 @@ func createAdClients(ns *v1.Namespace, t *testing.T, server *httptest.Server, sy
cloud, cloud,
plugins, plugins,
false, false,
time.Second*5) 5*time.Second,
timers)
if err != nil { if err != nil {
t.Fatalf("Error creating AttachDetach : %v", err) t.Fatalf("Error creating AttachDetach : %v", err)