func (e *RemoteCommandExecutor) Execute() error {
	doStdin := (e.stdin != nil)
	doStdout := (e.stdout != nil)
	doStderr := (!e.tty && e.stderr != nil)
	if doStdin {
		e.req.Param(api.ExecStdinParam, "1")
	}
	if doStdout {
		e.req.Param(api.ExecStdoutParam, "1")
	}
	if doStderr {
		e.req.Param(api.ExecStderrParam, "1")
	}
	if e.tty {
		e.req.Param(api.ExecTTYParam, "1")
	}
	for _, s := range e.command {
		e.req.Param(api.ExecCommandParamm, s)
	}
	if e.upgrader == nil {
		e.upgrader = &defaultUpgrader{}
	}
	conn, err := e.upgrader.upgrade(e.req, e.config)
	if err != nil {
		return err
	}
	defer conn.Close()
	doneChan := make(chan struct{}, 2)
	errorChan := make(chan error)
	cp := func(s string, dst io.Writer, src io.Reader) {
		glog.V(4).Infof("Copying %s", s)
		defer glog.V(4).Infof("Done copying %s", s)
		if _, err := io.Copy(dst, src); err != nil && err != io.EOF {
			glog.Errorf("Error copying %s: %v", s, err)
		}
		if s == api.StreamTypeStdout || s == api.StreamTypeStderr {
			doneChan <- struct{}{}
		}
	}
	headers := http.Header{}
	headers.Set(api.StreamType, api.StreamTypeError)
	errorStream, err := conn.CreateStream(headers)
	if err != nil {
		return err
	}
	go func() {
		message, err := ioutil.ReadAll(errorStream)
		if err != nil && err != io.EOF {
			errorChan <- fmt.Errorf("Error reading from error stream: %s", err)
			return
		}
		if len(message) > 0 {
			errorChan <- fmt.Errorf("Error executing remote command: %s", message)
			return
		}
	}()
	defer errorStream.Reset()
	if doStdin {
		headers.Set(api.StreamType, api.StreamTypeStdin)
		remoteStdin, err := conn.CreateStream(headers)
		if err != nil {
			return err
		}
		defer remoteStdin.Reset()
		go cp(api.StreamTypeStdin, remoteStdin, e.stdin)
	}
	waitCount := 0
	completedStreams := 0
	if doStdout {
		waitCount++
		headers.Set(api.StreamType, api.StreamTypeStdout)
		remoteStdout, err := conn.CreateStream(headers)
		if err != nil {
			return err
		}
		defer remoteStdout.Reset()
		go cp(api.StreamTypeStdout, e.stdout, remoteStdout)
	}
	if doStderr && !e.tty {
		waitCount++
		headers.Set(api.StreamType, api.StreamTypeStderr)
		remoteStderr, err := conn.CreateStream(headers)
		if err != nil {
			return err
		}
		defer remoteStderr.Reset()
		go cp(api.StreamTypeStderr, e.stderr, remoteStderr)
	}
Loop:
	for {
		select {
		case <-doneChan:
			completedStreams++
			if completedStreams == waitCount {
				break Loop
			}
		case err := <-errorChan:
			return err
		}
	}
	return nil
}
Execute sends a remote command execution request, upgrading the
connection and creating streams to represent stdin/stdout/stderr. Data is
copied between these streams and the supplied stdin/stdout/stderr parameters.
package remotecommand
import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/httpstream/spdy"
	"github.com/golang/glog"
)
type upgrader interface {
	upgrade(*client.Request, *client.Config) (httpstream.Connection, error)
}
type defaultUpgrader struct{}
func (u *defaultUpgrader) upgrade(req *client.Request, config *client.Config) (httpstream.Connection, error) {
	return req.Upgrade(config, spdy.NewRoundTripper)
}
type RemoteCommandExecutor struct {
	req     *client.Request
	config  *client.Config
	command []string
	stdin   io.Reader
	stdout  io.Writer
	stderr  io.Writer
	tty     bool
	upgrader upgrader
}
func New(req *client.Request, config *client.Config, command []string, stdin io.Reader, stdout, stderr io.Writer, tty bool) *RemoteCommandExecutor {
	return &RemoteCommandExecutor{
		req:     req,
		config:  config,
		command: command,
		stdin:   stdin,
		stdout:  stdout,
		stderr:  stderr,
		tty:     tty,
	}
}