Skip to content

Commit cd33be0

Browse files
christoph-zededarouming
authored andcommitted
execwrapper: reduce general timeout to 100s
before a timeout of 1000 seconds was used which is longer than the watchdog waits (currently 500 seconds) also switch to time.Duration to make time durations clearer Signed-off-by: Christoph Ostarek <[email protected]> (cherry picked from commit 193147f)
1 parent 26eea08 commit cd33be0

File tree

5 files changed

+66
-57
lines changed

5 files changed

+66
-57
lines changed

pkg/pillar/base/execwrapper.go

Lines changed: 44 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,84 +17,57 @@ import (
1717
)
1818

1919
const (
20-
// Will wait for 1000s max for a call instead of waiting forever
21-
maxTimeOutLimit = 1000
22-
timeOutLimit = 100
20+
/*
21+
* execution timeout is supposed to be less than the watchdog timeout,
22+
* as otherwise the watchdog might fire and reboot the system before
23+
* the timeout fires
24+
* exceptions are when an executable is started from a different goroutine
25+
* source of the error timeout and the watchdog timeout:
26+
* error timeout: $ grep -r errorTime pkg/pillar/cmd/ | grep time
27+
* watchdog timeout: $ grep hv_watchdog_timer pkg/grub/rootfs.cfg
28+
*/
29+
timeoutLimit = 3 * time.Minute
30+
defaultTimeout = 100 * time.Second
2331
)
2432

2533
// Command holds the necessary data to execute command
2634
type Command struct {
27-
command *exec.Cmd
28-
log *LogObject
29-
agentName string
30-
timeout time.Duration
31-
buffer *bytes.Buffer
32-
ctx context.Context
35+
command *exec.Cmd
36+
log *LogObject
37+
agentName string
38+
timeout time.Duration
39+
buffer *bytes.Buffer
40+
ctx context.Context
41+
errorMonad error
3342
}
3443

3544
// Output runs the command and returns its standard output.
3645
// Any returned error will usually be of type *ExitError.
37-
// Waits for the exec call to finish for `maxTimeOutLimit` after which timeout error is returned
46+
// Waits for the exec call to finish for `defaultTimeout` after which timeout error is returned
3847
func (c *Command) Output() ([]byte, error) {
3948
var buf bytes.Buffer
4049
c.command.Stdout = &buf
4150
c.buffer = &buf
42-
c.timeout = maxTimeOutLimit
51+
c.timeout = defaultTimeout
4352
return c.execCommand()
4453
}
4554

4655
// CombinedOutput runs the command and returns its combined standard output and standard error.
47-
// Waits for the exec call to finish for `maxTimeOutLimit` after which timeout error is returned
56+
// Waits for the exec call to finish for `defaultTimeout` after which timeout error is returned
4857
func (c *Command) CombinedOutput() ([]byte, error) {
4958
var buf bytes.Buffer
5059
c.command.Stdout = &buf
5160
c.command.Stderr = &buf
5261
c.buffer = &buf
53-
c.timeout = maxTimeOutLimit
54-
return c.execCommand()
55-
}
56-
57-
// OutputWithTimeout waits for the exec call to finish for `timeOutLimit`
58-
// after which timeout error is returned
59-
func (c *Command) OutputWithTimeout() ([]byte, error) {
60-
var buf bytes.Buffer
61-
c.command.Stdout = &buf
62-
c.buffer = &buf
63-
c.timeout = timeOutLimit
64-
return c.execCommand()
65-
}
66-
67-
// CombinedOutputWithTimeout waits for the exec call to finish for `timeOutLimit`
68-
// after which timeout error is returned
69-
func (c *Command) CombinedOutputWithTimeout() ([]byte, error) {
70-
var buf bytes.Buffer
71-
c.command.Stdout = &buf
72-
c.command.Stderr = &buf
73-
c.buffer = &buf
74-
c.timeout = timeOutLimit
75-
return c.execCommand()
76-
}
77-
78-
// OutputWithCustomTimeout accepts a custom timeout limit to wait for the exec call.
79-
func (c *Command) OutputWithCustomTimeout(timeout uint) ([]byte, error) {
80-
var buf bytes.Buffer
81-
c.command.Stdout = &buf
82-
c.buffer = &buf
83-
c.timeout = time.Duration(timeout)
84-
return c.execCommand()
85-
}
86-
87-
// CombinedOutputWithCustomTimeout accepts a custom timeout limit to wait for the exec call.
88-
func (c *Command) CombinedOutputWithCustomTimeout(timeout uint) ([]byte, error) {
89-
var buf bytes.Buffer
90-
c.command.Stdout = &buf
91-
c.command.Stderr = &buf
92-
c.buffer = &buf
93-
c.timeout = time.Duration(timeout)
62+
c.timeout = defaultTimeout
9463
return c.execCommand()
9564
}
9665

9766
func (c *Command) execCommand() ([]byte, error) {
67+
if c.errorMonad != nil {
68+
return nil, c.errorMonad
69+
}
70+
9871
if c.log != nil {
9972
c.log.Tracef("execCommand(%v)", c.command.Args)
10073
}
@@ -108,7 +81,7 @@ func (c *Command) execCommand() ([]byte, error) {
10881
stillRunning := time.NewTicker(25 * time.Second)
10982
defer stillRunning.Stop()
11083

111-
waitTimer := time.NewTimer(c.timeout * time.Second)
84+
waitTimer := time.NewTimer(c.timeout)
11285
defer waitTimer.Stop()
11386

11487
if c.ctx == nil {
@@ -134,6 +107,23 @@ func (c *Command) execCommand() ([]byte, error) {
134107
}
135108
}
136109

110+
// WithLimitedTimeout set custom timeout for command
111+
func (c *Command) WithLimitedTimeout(timeout time.Duration) *Command {
112+
c.timeout = timeout
113+
if c.timeout > timeoutLimit {
114+
c.errorMonad = fmt.Errorf("custom timeout (%v) is longer than watchdog timeout (%v)", c.timeout, defaultTimeout)
115+
}
116+
117+
return c
118+
}
119+
120+
// WithUnlimitedTimeout set custom timeout for command not bound to any limits for when run in a separate goroutine
121+
func (c *Command) WithUnlimitedTimeout(timeout time.Duration) *Command {
122+
c.timeout = timeout
123+
124+
return c
125+
}
126+
137127
// WithContext set context for command
138128
func (c *Command) WithContext(ctx context.Context) *Command {
139129
c.ctx = ctx
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package base_test
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/lf-edge/eve/pkg/pillar/base"
8+
)
9+
10+
func TestTimeoutLongerThanLimit(t *testing.T) {
11+
t.Parallel()
12+
13+
timeout := 600 * time.Second
14+
_, err := base.Exec(nil, "/bin/true").WithLimitedTimeout(timeout).CombinedOutput()
15+
if err == nil {
16+
t.Fatalf("Execution should fail with timeout too long, but succeeded")
17+
}
18+
}

pkg/pillar/cmd/domainmgr/domainmgr.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2658,7 +2658,7 @@ func mkisofs(output string, dir string) error {
26582658
dir,
26592659
}
26602660
log.Functionf("Calling command %s %v\n", cmd, args)
2661-
stdoutStderr, err := base.Exec(log, cmd, args...).CombinedOutput()
2661+
stdoutStderr, err := base.Exec(log, cmd, args...).WithUnlimitedTimeout(15 * time.Minute).CombinedOutput()
26622662
if err != nil {
26632663
errStr := fmt.Sprintf("mkisofs failed: %s",
26642664
string(stdoutStderr))

pkg/pillar/diskmetrics/diskmetrics.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"os"
1212
"strconv"
1313
"strings"
14+
"time"
1415

1516
"github.com/lf-edge/eve/pkg/pillar/base"
1617
"github.com/lf-edge/eve/pkg/pillar/types"
@@ -93,7 +94,7 @@ func RolloutImgToBlock(ctx context.Context, log *base.LogObject, diskfile, outpu
9394
// writeback cache instead of default unsafe, out of order enabled, skip file creation
9495
// Timeout 2 hours
9596
args := []string{"convert", "--target-is-zero", "-t", "writeback", "-W", "-n", "-O", outputFormat, diskfile, outputFile}
96-
output, err := base.Exec(log, "/usr/bin/qemu-img", args...).WithContext(ctx).CombinedOutputWithCustomTimeout(432000)
97+
output, err := base.Exec(log, "/usr/bin/qemu-img", args...).WithContext(ctx).WithUnlimitedTimeout(15 * time.Minute).CombinedOutput()
9798
if err != nil {
9899
errStr := fmt.Sprintf("qemu-img failed: %s, %s\n",
99100
err, output)

pkg/pillar/netmonitor/linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ func (m *LinuxNetworkMonitor) GetInterfaceDHCPInfo(ifIndex int) (info DHCPInfo,
257257
// XXX Getting error -1 unless we add argument -4.
258258
// XXX Add IPv6 support.
259259
m.Log.Functionf("Calling dhcpcd -U -4 %s\n", ifName)
260-
stdoutStderr, err := base.Exec(m.Log, "dhcpcd", "-U", "-4", ifName).CombinedOutputWithTimeout()
260+
stdoutStderr, err := base.Exec(m.Log, "dhcpcd", "-U", "-4", ifName).CombinedOutput()
261261
if err != nil {
262262
if strings.Contains(string(stdoutStderr), "dhcp_dump: No such file or directory") {
263263
// DHCP is not configured for this interface. Return empty DHCPInfo.

0 commit comments

Comments
 (0)