mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 05:27:21 +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
|
// and skips if a disk of that type does not exist on the node
|
||||||
func SkipUnlessLocalSSDExists(config *localTestConfig, ssdInterface, filesystemType string, node *v1.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)
|
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)
|
framework.ExpectNoError(err)
|
||||||
num, err := strconv.Atoi(strings.TrimSpace(res))
|
num, err := strconv.Atoi(strings.TrimSpace(res.Stdout))
|
||||||
framework.ExpectNoError(err)
|
framework.ExpectNoError(err)
|
||||||
if num < 1 {
|
if num < 1 {
|
||||||
framework.Skipf("Requires at least 1 %s %s localSSD ", ssdInterface, filesystemType)
|
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/uuid:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait: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/kubernetes:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/util/exec:go_default_library",
|
||||||
"//test/e2e/framework: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/node:go_default_library",
|
||||||
"//test/e2e/framework/pod:go_default_library",
|
"//test/e2e/framework/pod:go_default_library",
|
||||||
"//test/e2e/framework/ssh:go_default_library",
|
"//test/e2e/framework/ssh:go_default_library",
|
||||||
|
@ -20,12 +20,33 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/client-go/util/exec"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
|
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
|
||||||
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
|
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.
|
// HostExec represents interface we require to execute commands on remote host.
|
||||||
type HostExec interface {
|
type HostExec interface {
|
||||||
|
Execute(cmd string, node *v1.Node) (Result, error)
|
||||||
IssueCommandWithResult(cmd string, node *v1.Node) (string, error)
|
IssueCommandWithResult(cmd string, node *v1.Node) (string, error)
|
||||||
IssueCommand(cmd string, node *v1.Node) error
|
IssueCommand(cmd string, node *v1.Node) error
|
||||||
Cleanup()
|
Cleanup()
|
||||||
@ -84,21 +105,35 @@ func (h *hostExecutor) launchNodeExecPod(node string) *v1.Pod {
|
|||||||
return pod
|
return pod
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssueCommandWithResult issues command on given node and returns stdout.
|
// Execute executes the command on the given node. If there is no error
|
||||||
func (h *hostExecutor) IssueCommandWithResult(cmd string, node *v1.Node) (string, 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]
|
pod, ok := h.nodeExecPods[node.Name]
|
||||||
if !ok {
|
if !ok {
|
||||||
pod = h.launchNodeExecPod(node.Name)
|
pod = h.launchNodeExecPod(node.Name)
|
||||||
if pod == nil {
|
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
|
h.nodeExecPods[node.Name] = pod
|
||||||
}
|
}
|
||||||
args := []string{
|
args := []string{
|
||||||
"exec",
|
|
||||||
fmt.Sprintf("--namespace=%v", pod.Namespace),
|
|
||||||
pod.Name,
|
|
||||||
"--",
|
|
||||||
"nsenter",
|
"nsenter",
|
||||||
"--mount=/rootfs/proc/1/ns/mnt",
|
"--mount=/rootfs/proc/1/ns/mnt",
|
||||||
"--",
|
"--",
|
||||||
@ -106,7 +141,27 @@ func (h *hostExecutor) IssueCommandWithResult(cmd string, node *v1.Node) (string
|
|||||||
"-c",
|
"-c",
|
||||||
cmd,
|
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.
|
// IssueCommand works like IssueCommandWithResult, but discards result.
|
||||||
|
Loading…
Reference in New Issue
Block a user