mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
better HostExec
- separate stdout and stderr - return command exit code - remove kubectl dependency
This commit is contained in:
parent
9832418870
commit
d8c465c8d7
@ -1182,9 +1182,10 @@ func validateStatefulSet(config *localTestConfig, ss *appsv1.StatefulSet, anti b
|
||||
// and skips if a disk of that type does not exist on the node
|
||||
func SkipUnlessLocalSSDExists(config *localTestConfig, ssdInterface, filesystemType string, node *v1.Node) {
|
||||
ssdCmd := fmt.Sprintf("ls -1 /mnt/disks/by-uuid/google-local-ssds-%s-%s/ | wc -l", ssdInterface, filesystemType)
|
||||
res, err := config.hostExec.IssueCommandWithResult(ssdCmd, node)
|
||||
res, err := config.hostExec.Execute(ssdCmd, node)
|
||||
utils.LogResult(res)
|
||||
framework.ExpectNoError(err)
|
||||
num, err := strconv.Atoi(strings.TrimSpace(res))
|
||||
num, err := strconv.Atoi(strings.TrimSpace(res.Stdout))
|
||||
framework.ExpectNoError(err)
|
||||
if num < 1 {
|
||||
framework.Skipf("Requires at least 1 %s %s localSSD ", ssdInterface, filesystemType)
|
||||
|
@ -26,7 +26,9 @@ go_library(
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/exec:go_default_library",
|
||||
"//test/e2e/framework:go_default_library",
|
||||
"//test/e2e/framework/log:go_default_library",
|
||||
"//test/e2e/framework/node:go_default_library",
|
||||
"//test/e2e/framework/pod:go_default_library",
|
||||
"//test/e2e/framework/ssh:go_default_library",
|
||||
|
@ -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 {
|
||||
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)
|
||||
}
|
||||
|
||||
// HostExec represents interface we require to execute commands on remote host.
|
||||
type HostExec interface {
|
||||
Execute(cmd string, node *v1.Node) (Result, error)
|
||||
IssueCommandWithResult(cmd string, node *v1.Node) (string, error)
|
||||
IssueCommand(cmd string, node *v1.Node) error
|
||||
Cleanup()
|
||||
@ -84,21 +105,35 @@ 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 {
|
||||
// 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]
|
||||
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",
|
||||
"--",
|
||||
@ -106,7 +141,27 @@ func (h *hostExecutor) IssueCommandWithResult(cmd string, node *v1.Node) (string
|
||||
"-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.
|
||||
|
Loading…
Reference in New Issue
Block a user