github.com/pdmccormick/importable-docker-buildx@v0.0.0-20240426161518-e47091289030/driver/kubernetes/execconn/execconn.go (about) 1 package execconn 2 3 import ( 4 "context" 5 "io" 6 "net" 7 "os" 8 "sync" 9 "time" 10 11 "github.com/sirupsen/logrus" 12 corev1 "k8s.io/api/core/v1" 13 "k8s.io/client-go/kubernetes/scheme" 14 "k8s.io/client-go/rest" 15 "k8s.io/client-go/tools/remotecommand" 16 ) 17 18 func ExecConn(ctx context.Context, restClient rest.Interface, restConfig *rest.Config, namespace, pod, container string, cmd []string) (net.Conn, error) { 19 req := restClient. 20 Post(). 21 Namespace(namespace). 22 Resource("pods"). 23 Name(pod). 24 SubResource("exec"). 25 VersionedParams(&corev1.PodExecOptions{ 26 Container: container, 27 Command: cmd, 28 Stdin: true, 29 Stdout: true, 30 Stderr: true, 31 TTY: false, 32 }, scheme.ParameterCodec) 33 exec, err := remotecommand.NewSPDYExecutor(restConfig, "POST", req.URL()) 34 if err != nil { 35 return nil, err 36 } 37 stdinR, stdinW := io.Pipe() 38 stdoutR, stdoutW := io.Pipe() 39 kc := &kubeConn{ 40 stdin: stdinW, 41 stdout: stdoutR, 42 localAddr: dummyAddr{network: "dummy", s: "dummy-0"}, 43 remoteAddr: dummyAddr{network: "dummy", s: "dummy-1"}, 44 } 45 go func() { 46 serr := exec.StreamWithContext(ctx, remotecommand.StreamOptions{ 47 Stdin: stdinR, 48 Stdout: stdoutW, 49 Stderr: os.Stderr, 50 Tty: false, 51 }) 52 if serr != nil && serr != context.Canceled { 53 logrus.Error(serr) 54 } 55 }() 56 return kc, nil 57 } 58 59 type kubeConn struct { 60 stdin io.WriteCloser 61 stdout io.ReadCloser 62 stdioClosedMu sync.Mutex // for stdinClosed and stdoutClosed 63 stdinClosed bool 64 stdoutClosed bool 65 localAddr net.Addr 66 remoteAddr net.Addr 67 } 68 69 func (c *kubeConn) Write(p []byte) (int, error) { 70 return c.stdin.Write(p) 71 } 72 73 func (c *kubeConn) Read(p []byte) (int, error) { 74 return c.stdout.Read(p) 75 } 76 77 func (c *kubeConn) CloseWrite() error { 78 err := c.stdin.Close() 79 c.stdioClosedMu.Lock() 80 c.stdinClosed = true 81 c.stdioClosedMu.Unlock() 82 return err 83 } 84 func (c *kubeConn) CloseRead() error { 85 err := c.stdout.Close() 86 c.stdioClosedMu.Lock() 87 c.stdoutClosed = true 88 c.stdioClosedMu.Unlock() 89 return err 90 } 91 92 func (c *kubeConn) Close() error { 93 var err error 94 c.stdioClosedMu.Lock() 95 stdinClosed := c.stdinClosed 96 c.stdioClosedMu.Unlock() 97 if !stdinClosed { 98 err = c.CloseWrite() 99 } 100 c.stdioClosedMu.Lock() 101 stdoutClosed := c.stdoutClosed 102 c.stdioClosedMu.Unlock() 103 if !stdoutClosed { 104 err = c.CloseRead() 105 } 106 return err 107 } 108 109 func (c *kubeConn) LocalAddr() net.Addr { 110 return c.localAddr 111 } 112 func (c *kubeConn) RemoteAddr() net.Addr { 113 return c.remoteAddr 114 } 115 func (c *kubeConn) SetDeadline(t time.Time) error { 116 return nil 117 } 118 func (c *kubeConn) SetReadDeadline(t time.Time) error { 119 return nil 120 } 121 func (c *kubeConn) SetWriteDeadline(t time.Time) error { 122 return nil 123 } 124 125 type dummyAddr struct { 126 network string 127 s string 128 } 129 130 func (d dummyAddr) Network() string { 131 return d.network 132 } 133 134 func (d dummyAddr) String() string { 135 return d.s 136 }