Go Client - exec-ing a shel command in pod


#1

Hello community,

I have the following code, leveraging the Kubernetes go client for executing a shell command in a pod programmatically:

// ExecuteRemoteCommand executes a remote shell command on the given pod
// returns the output from stdout and stderr
func ExecuteRemoteCommand(pod *v1.Pod, command string) (string, string, error) {
	kubeCfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		clientcmd.NewDefaultClientConfigLoadingRules(),
		&clientcmd.ConfigOverrides{},
	)
	restCfg, err := kubeCfg.ClientConfig()
	if err != nil {
		return "", "", err
	}
	coreClient, err := corev1client.NewForConfig(restCfg)
	if err != nil {
		return "", "", err
	}

	buf := &bytes.Buffer{}
	errBuf := &bytes.Buffer{}
	request := coreClient.RESTClient().
		Post().
		Namespace(pod.Namespace).
		Resource("pods").
		Name(pod.Name).
		SubResource("exec").
		VersionedParams(&k8s_corev1.PodExecOptions{
			Command: []string{"/bin/sh", "-c", command},
			Stdin:   true,
			Stdout:  true,
			Stderr:  true,
			TTY:     true,
		}, scheme.ParameterCodec)
	exec, err := remotecommand.NewSPDYExecutor(restCfg, "POST", request.URL())
	err = exec.Stream(remotecommand.StreamOptions{
		Stdout: buf,
		Stderr: errBuf,
	})
	if err != nil {
		return "", "", errors.Wrapf(err, "Failed executing command %s on %v/%v", command, pod.Namespace, pod.Name)
	}

	return buf.String(), errBuf.String(), nil
}

I find there is some flakiness in this code - I sometimes get output from the shell command and I sometimes don’t. The command I’m using it ls, so it should always return some output.

exec.Stream() is synchronous, right?

Has anybody had any experience with similar functionality?


#2

I’ve faced same question, the reason I found should be this: when you input the cmd to execute in container/pod, you may lost ‘LF’ or ‘CR’, cmd cannot be execute, so there is no output.

So I changed input methods, just like Kubernetes/dashboard, using sockJs to send cmd to pod/container. sockJs will do the job to add ‘LF’ or ‘CR’, every cmd input would be a whole executable cmd, so we can get the correct output.


#3

I realized what the problem in that piece of code was - it’s the stdin argument. Setting it to false fixed my issue.