Skip to content

Commit eebdd9a

Browse files
committed
Implement retry logic of the drain operation itself
Signed-off-by: Georg Doser <georg.doser@nitrado.net>
1 parent 978f585 commit eebdd9a

1 file changed

Lines changed: 42 additions & 11 deletions

File tree

cmd/kured/main.go

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ var (
4343
forceReboot bool
4444
drainDelay time.Duration
4545
drainTimeout time.Duration
46+
globalDrainTimeout time.Duration
4647
rebootDelay time.Duration
4748
rebootMethod string
4849
period time.Duration
@@ -129,6 +130,8 @@ func main() {
129130
flag.DurationVar(&drainDelay, "drain-delay", 0,
130131
"delay drain for this duration (default: 0, disabled)")
131132
flag.DurationVar(&drainTimeout, "drain-timeout", 0,
133+
"timeout after which an individual drain is aborted if global-drain-timeout is not set this is the full timeout (default: 0, infinite time)")
134+
flag.DurationVar(&globalDrainTimeout, "global-drain-timeout", 0,
132135
"timeout after which the drain is aborted (default: 0, infinite time)")
133136
flag.DurationVar(&rebootDelay, "reboot-delay", 0,
134137
"delay reboot for this duration (default: 0, disabled)")
@@ -214,6 +217,9 @@ func main() {
214217
log.Fatal("KURED_NODE_ID environment variable required")
215218
}
216219
log.Infof("Node ID: %s", nodeID)
220+
if globalDrainTimeout > 0 && drainTimeout == 0 {
221+
log.Fatal("global-drain-timeout is set, but drain-timeout is not set. Please set drain-timeout to a value greater than 0.")
222+
}
217223

218224
notifyURL = validateNotificationURL(notifyURL, slackHookURL)
219225

@@ -616,6 +622,7 @@ func rebootAsRequired(nodeID string, rebooter reboot.Rebooter, checker checkers.
616622

617623
source = rand.NewSource(time.Now().UnixNano())
618624
tick = delaytick.New(source, period)
625+
MAIN:
619626
for range tick {
620627
if !window.Contains(time.Now()) {
621628
// Remove taint outside the reboot time window to allow for normal operation.
@@ -676,18 +683,42 @@ func rebootAsRequired(nodeID string, rebooter reboot.Rebooter, checker checkers.
676683
continue
677684
}
678685
}
679-
680-
err = drain(client, node)
681-
if err != nil {
682-
if !forceReboot {
683-
log.Errorf("Unable to cordon or drain %s: %v, will release lock and retry cordon and drain before rebooting when lock is next acquired", node.GetName(), err)
684-
err = lock.Release()
685-
if err != nil {
686-
log.Errorf("Error releasing lock: %v", err)
686+
if globalDrainTimeout == 0 {
687+
err = drain(client, node)
688+
if err != nil {
689+
if !forceReboot {
690+
log.Errorf("Unable to cordon or drain %s: %v, will release lock and retry cordon and drain before rebooting when lock is next acquired", node.GetName(), err)
691+
err = lock.Release()
692+
if err != nil {
693+
log.Errorf("Error releasing lock: %v", err)
694+
}
695+
log.Infof("Performing a best-effort uncordon after failed cordon and drain")
696+
uncordon(client, node)
697+
continue
698+
}
699+
}
700+
} else {
701+
deadline := time.Now().Add(globalDrainTimeout)
702+
for {
703+
if time.Now().After(deadline) {
704+
log.Errorf("Drain timed out after global timeout (%v) for node %s", globalDrainTimeout, node.GetName())
705+
if !forceReboot {
706+
err = lock.Release()
707+
if err != nil {
708+
log.Errorf("Error releasing lock: %v", err)
709+
}
710+
log.Infof("Performing a best-effort uncordon after failed cordon and drain")
711+
uncordon(client, node)
712+
time.Sleep(period * 2) // Wait at least two periods before retrying, giving other nodes a chance to drain instead
713+
continue MAIN
714+
}
715+
break
716+
}
717+
err = drain(client, node)
718+
if err == nil {
719+
// Drain was successful, break out of the loop
720+
break
687721
}
688-
log.Infof("Performing a best-effort uncordon after failed cordon and drain")
689-
uncordon(client, node)
690-
continue
691722
}
692723
}
693724

0 commit comments

Comments
 (0)