@@ -17,84 +17,57 @@ import (
17
17
)
18
18
19
19
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
23
31
)
24
32
25
33
// Command holds the necessary data to execute command
26
34
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
33
42
}
34
43
35
44
// Output runs the command and returns its standard output.
36
45
// 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
38
47
func (c * Command ) Output () ([]byte , error ) {
39
48
var buf bytes.Buffer
40
49
c .command .Stdout = & buf
41
50
c .buffer = & buf
42
- c .timeout = maxTimeOutLimit
51
+ c .timeout = defaultTimeout
43
52
return c .execCommand ()
44
53
}
45
54
46
55
// 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
48
57
func (c * Command ) CombinedOutput () ([]byte , error ) {
49
58
var buf bytes.Buffer
50
59
c .command .Stdout = & buf
51
60
c .command .Stderr = & buf
52
61
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
94
63
return c .execCommand ()
95
64
}
96
65
97
66
func (c * Command ) execCommand () ([]byte , error ) {
67
+ if c .errorMonad != nil {
68
+ return nil , c .errorMonad
69
+ }
70
+
98
71
if c .log != nil {
99
72
c .log .Tracef ("execCommand(%v)" , c .command .Args )
100
73
}
@@ -108,7 +81,7 @@ func (c *Command) execCommand() ([]byte, error) {
108
81
stillRunning := time .NewTicker (25 * time .Second )
109
82
defer stillRunning .Stop ()
110
83
111
- waitTimer := time .NewTimer (c .timeout * time . Second )
84
+ waitTimer := time .NewTimer (c .timeout )
112
85
defer waitTimer .Stop ()
113
86
114
87
if c .ctx == nil {
@@ -134,6 +107,23 @@ func (c *Command) execCommand() ([]byte, error) {
134
107
}
135
108
}
136
109
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
+
137
127
// WithContext set context for command
138
128
func (c * Command ) WithContext (ctx context.Context ) * Command {
139
129
c .ctx = ctx
0 commit comments