New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve e2e HostExec utility #84444
Improve e2e HostExec utility #84444
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,12 +20,33 @@ import ( | |
"fmt" | ||
|
||
v1 "k8s.io/api/core/v1" | ||
"k8s.io/client-go/util/exec" | ||
"k8s.io/kubernetes/test/e2e/framework" | ||
e2elog "k8s.io/kubernetes/test/e2e/framework/log" | ||
e2epod "k8s.io/kubernetes/test/e2e/framework/pod" | ||
) | ||
|
||
// Result holds the execution result of remote execution command. | ||
type Result struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like |
||
Host string | ||
Cmd string | ||
Stdout string | ||
Stderr string | ||
Code int | ||
} | ||
|
||
// LogResult records result log | ||
func LogResult(result Result) { | ||
remote := result.Host | ||
e2elog.Logf("exec %s: command: %s", remote, result.Cmd) | ||
e2elog.Logf("exec %s: stdout: %q", remote, result.Stdout) | ||
e2elog.Logf("exec %s: stderr: %q", remote, result.Stderr) | ||
e2elog.Logf("exec %s: exit code: %d", remote, result.Code) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. like
failed command log:
|
||
} | ||
|
||
// HostExec represents interface we require to execute commands on remote host. | ||
type HostExec interface { | ||
Execute(cmd string, node *v1.Node) (Result, error) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New method to replace |
||
IssueCommandWithResult(cmd string, node *v1.Node) (string, error) | ||
IssueCommand(cmd string, node *v1.Node) error | ||
Cleanup() | ||
|
@@ -84,29 +105,63 @@ func (h *hostExecutor) launchNodeExecPod(node string) *v1.Pod { | |
return pod | ||
} | ||
|
||
// IssueCommandWithResult issues command on given node and returns stdout. | ||
func (h *hostExecutor) IssueCommandWithResult(cmd string, node *v1.Node) (string, error) { | ||
// Execute executes the command on the given node. If there is no error | ||
// performing the remote command execution, the stdout, stderr and exit code | ||
// are returned. | ||
// This works like ssh.SSH(...) utility. | ||
func (h *hostExecutor) Execute(cmd string, node *v1.Node) (Result, error) { | ||
result, err := h.exec(cmd, node) | ||
if codeExitErr, ok := err.(exec.CodeExitError); ok { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
// extract the exit code of remote command and silence the command | ||
// non-zero exit code error | ||
result.Code = codeExitErr.ExitStatus() | ||
err = nil | ||
} | ||
return result, err | ||
} | ||
|
||
func (h *hostExecutor) exec(cmd string, node *v1.Node) (Result, error) { | ||
result := Result{ | ||
Host: node.Name, | ||
Cmd: cmd, | ||
} | ||
pod, ok := h.nodeExecPods[node.Name] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I remember @jsafrane hit some issue with creating two host exec pods in the same test. Did that ever get resolved? How about hostexec for two tests running in parallel? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A limitation is this utility cannot be shared by multiple parallel tests. We can add support when necessary. |
||
if !ok { | ||
pod = h.launchNodeExecPod(node.Name) | ||
if pod == nil { | ||
return "", fmt.Errorf("failed to create hostexec pod for node %q", node) | ||
return result, fmt.Errorf("failed to create hostexec pod for node %q", node) | ||
} | ||
h.nodeExecPods[node.Name] = pod | ||
} | ||
args := []string{ | ||
"exec", | ||
fmt.Sprintf("--namespace=%v", pod.Namespace), | ||
pod.Name, | ||
"--", | ||
"nsenter", | ||
"--mount=/rootfs/proc/1/ns/mnt", | ||
"--", | ||
"sh", | ||
"-c", | ||
cmd, | ||
} | ||
return framework.RunKubectl(args...) | ||
containerName := pod.Spec.Containers[0].Name | ||
var err error | ||
result.Stdout, result.Stderr, err = h.Framework.ExecWithOptions(framework.ExecOptions{ | ||
Command: args, | ||
Namespace: pod.Namespace, | ||
PodName: pod.Name, | ||
ContainerName: containerName, | ||
Stdin: nil, | ||
CaptureStdout: true, | ||
CaptureStderr: true, | ||
PreserveWhitespace: true, | ||
}) | ||
return result, err | ||
} | ||
|
||
// IssueCommandWithResult issues command on the given node and returns stdout as | ||
// result. It returns error if there are some issues executing the command or | ||
// the command exits non-zero. | ||
func (h *hostExecutor) IssueCommandWithResult(cmd string, node *v1.Node) (string, error) { | ||
result, err := h.exec(cmd, node) | ||
return result.Stdout, err | ||
} | ||
|
||
// IssueCommand works like IssueCommandWithResult, but discards result. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as an example usage of
Execute
method. I didn't remove allIssueCommand/IssueCommandWithResult
use cases. These two methods are simple to use sometimes.