Merge pull request #63332 from zhouhaibing089/exec-timeout

Automatic merge from submit-queue (batch tested with PRs 63792, 63495, 63742, 63332, 63779). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

add timeout for exec interface

This should get us away from situations like https://github.com/kubernetes/kubernetes/issues/63331.

A little bit more context, the `os/exec` package starts to accept `context.Context` in golang 1.7. We should leverage that so we can have a more predictable behavior, then. 

```release-note
NONE
```
This commit is contained in:
Kubernetes Submit Queue
2018-05-15 09:04:28 -07:00
committed by GitHub
4 changed files with 61 additions and 27 deletions

53
vendor/k8s.io/utils/exec/exec.go generated vendored
View File

@@ -17,6 +17,7 @@ limitations under the License.
package exec
import (
"context"
"io"
osexec "os/exec"
"syscall"
@@ -33,6 +34,13 @@ type Interface interface {
// This follows the pattern of package os/exec.
Command(cmd string, args ...string) Cmd
// CommandContext returns a Cmd instance which can be used to run a single command.
//
// The provided context is used to kill the process if the context becomes done
// before the command completes on its own. For example, a timeout can be set in
// the context.
CommandContext(ctx context.Context, cmd string, args ...string) Cmd
// LookPath wraps os/exec.LookPath
LookPath(file string) (string, error)
}
@@ -82,6 +90,11 @@ func (executor *executor) Command(cmd string, args ...string) Cmd {
return (*cmdWrapper)(osexec.Command(cmd, args...))
}
// CommandContext is part of the Interface interface.
func (executor *executor) CommandContext(ctx context.Context, cmd string, args ...string) Cmd {
return (*cmdWrapper)(osexec.CommandContext(ctx, cmd, args...))
}
// LookPath is part of the Interface interface
func (executor *executor) LookPath(file string) (string, error) {
return osexec.LookPath(file)
@@ -110,52 +123,52 @@ func (cmd *cmdWrapper) SetStderr(out io.Writer) {
// Run is part of the Cmd interface.
func (cmd *cmdWrapper) Run() error {
return (*osexec.Cmd)(cmd).Run()
err := (*osexec.Cmd)(cmd).Run()
return handleError(err)
}
// CombinedOutput is part of the Cmd interface.
func (cmd *cmdWrapper) CombinedOutput() ([]byte, error) {
out, err := (*osexec.Cmd)(cmd).CombinedOutput()
if err != nil {
return out, handleError(err)
}
return out, nil
return out, handleError(err)
}
func (cmd *cmdWrapper) Output() ([]byte, error) {
out, err := (*osexec.Cmd)(cmd).Output()
if err != nil {
return out, handleError(err)
}
return out, nil
return out, handleError(err)
}
// Stop is part of the Cmd interface.
func (cmd *cmdWrapper) Stop() {
c := (*osexec.Cmd)(cmd)
if c.ProcessState.Exited() {
if c.Process == nil {
return
}
c.Process.Signal(syscall.SIGTERM)
time.AfterFunc(10*time.Second, func() {
if c.ProcessState.Exited() {
return
if !c.ProcessState.Exited() {
c.Process.Signal(syscall.SIGKILL)
}
c.Process.Signal(syscall.SIGKILL)
})
}
func handleError(err error) error {
if ee, ok := err.(*osexec.ExitError); ok {
// Force a compile fail if exitErrorWrapper can't convert to ExitError.
var x ExitError = &ExitErrorWrapper{ee}
return x
if err == nil {
return nil
}
if ee, ok := err.(*osexec.Error); ok {
if ee.Err == osexec.ErrNotFound {
switch e := err.(type) {
case *osexec.ExitError:
return &ExitErrorWrapper{e}
case *osexec.Error:
if e.Err == osexec.ErrNotFound {
return ErrExecutableNotFound
}
}
return err
}
@@ -165,7 +178,7 @@ type ExitErrorWrapper struct {
*osexec.ExitError
}
var _ ExitError = ExitErrorWrapper{}
var _ ExitError = &ExitErrorWrapper{}
// ExitStatus is part of the ExitError interface.
func (eew ExitErrorWrapper) ExitStatus() int {

View File

@@ -17,6 +17,7 @@ limitations under the License.
package testingexec
import (
"context"
"fmt"
"io"
@@ -30,6 +31,8 @@ type FakeExec struct {
LookPathFunc func(string) (string, error)
}
var _ exec.Interface = &FakeExec{}
type FakeCommandAction func(cmd string, args ...string) exec.Cmd
func (fake *FakeExec) Command(cmd string, args ...string) exec.Cmd {
@@ -41,6 +44,10 @@ func (fake *FakeExec) Command(cmd string, args ...string) exec.Cmd {
return fake.CommandScript[i](cmd, args...)
}
func (fake *FakeExec) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd {
return fake.Command(cmd, args...)
}
func (fake *FakeExec) LookPath(file string) (string, error) {
return fake.LookPathFunc(file)
}