| 89 | } |
| 90 | |
| 91 | func (p *streamProtocolV2) copyStdin() { |
| 92 | if p.Stdin != nil { |
| 93 | var once sync.Once |
| 94 | |
| 95 | // copy from client's stdin to container's stdin |
| 96 | go func() { |
| 97 | defer runtime.HandleCrash() |
| 98 | |
| 99 | // if p.stdin is noninteractive, p.g. `echo abc | kubectl exec -i <pod> -- cat`, make sure |
| 100 | // we close remoteStdin as soon as the copy from p.stdin to remoteStdin finishes. Otherwise |
| 101 | // the executed command will remain running. |
| 102 | defer once.Do(func() { p.remoteStdin.Close() }) |
| 103 | |
| 104 | if _, err := io.Copy(p.remoteStdin, readerWrapper{p.Stdin}); err != nil { |
| 105 | runtime.HandleError(err) |
| 106 | } |
| 107 | }() |
| 108 | |
| 109 | // read from remoteStdin until the stream is closed. this is essential to |
| 110 | // be able to exit interactive sessions cleanly and not leak goroutines or |
| 111 | // hang the client's terminal. |
| 112 | // |
| 113 | // TODO we aren't using go-dockerclient any more; revisit this to determine if it's still |
| 114 | // required by engine-api. |
| 115 | // |
| 116 | // go-dockerclient's current hijack implementation |
| 117 | // (https://github.com/fsouza/go-dockerclient/blob/89f3d56d93788dfe85f864a44f85d9738fca0670/client.go#L564) |
| 118 | // waits for all three streams (stdin/stdout/stderr) to finish copying |
| 119 | // before returning. When hijack finishes copying stdout/stderr, it calls |
| 120 | // Close() on its side of remoteStdin, which allows this copy to complete. |
| 121 | // When that happens, we must Close() on our side of remoteStdin, to |
| 122 | // allow the copy in hijack to complete, and hijack to return. |
| 123 | go func() { |
| 124 | defer runtime.HandleCrash() |
| 125 | defer once.Do(func() { p.remoteStdin.Close() }) |
| 126 | |
| 127 | // this "copy" doesn't actually read anything - it's just here to wait for |
| 128 | // the server to close remoteStdin. |
| 129 | if _, err := io.Copy(ioutil.Discard, p.remoteStdin); err != nil { |
| 130 | runtime.HandleError(err) |
| 131 | } |
| 132 | }() |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | func (p *streamProtocolV2) copyStdout(wg *sync.WaitGroup) { |
| 137 | if p.Stdout == nil { |