github.com/secure-build/gitlab-runner@v12.5.0+incompatible/executors/kubernetes/terminal.go (about) 1 package kubernetes 2 3 import ( 4 "io/ioutil" 5 "net/http" 6 "net/url" 7 8 terminal "gitlab.com/gitlab-org/gitlab-terminal" 9 api "k8s.io/api/core/v1" 10 "k8s.io/client-go/kubernetes/scheme" 11 restclient "k8s.io/client-go/rest" 12 13 "gitlab.com/gitlab-org/gitlab-runner/session/proxy" 14 terminalsession "gitlab.com/gitlab-org/gitlab-runner/session/terminal" 15 ) 16 17 func (s *executor) Connect() (terminalsession.Conn, error) { 18 settings, err := s.getTerminalSettings() 19 if err != nil { 20 return nil, err 21 } 22 23 return terminalConn{settings: settings}, nil 24 } 25 26 type terminalConn struct { 27 settings *terminal.TerminalSettings 28 } 29 30 func (t terminalConn) Start(w http.ResponseWriter, r *http.Request, timeoutCh, disconnectCh chan error) { 31 wsProxy := terminal.NewWebSocketProxy(1) // one stopper: terminal exit handler 32 33 terminalsession.ProxyTerminal( 34 timeoutCh, 35 disconnectCh, 36 wsProxy.StopCh, 37 func() { 38 terminal.ProxyWebSocket(w, r, t.settings, wsProxy) 39 }, 40 ) 41 } 42 43 func (t terminalConn) Close() error { 44 return nil 45 } 46 47 func (s *executor) getTerminalSettings() (*terminal.TerminalSettings, error) { 48 config, err := getKubeClientConfig(s.Config.Kubernetes, s.configurationOverwrites) 49 if err != nil { 50 return nil, err 51 } 52 53 wsURL, err := s.getTerminalWebSocketURL(config) 54 if err != nil { 55 return nil, err 56 } 57 58 caCert := "" 59 if len(config.CAFile) > 0 { 60 buf, err := ioutil.ReadFile(config.CAFile) 61 if err != nil { 62 return nil, err 63 } 64 caCert = string(buf) 65 } 66 67 term := &terminal.TerminalSettings{ 68 Subprotocols: []string{"channel.k8s.io"}, 69 Url: wsURL.String(), 70 Header: http.Header{"Authorization": []string{"Bearer " + config.BearerToken}}, 71 CAPem: caCert, 72 MaxSessionTime: 0, 73 } 74 75 return term, nil 76 } 77 78 func (s *executor) getTerminalWebSocketURL(config *restclient.Config) (*url.URL, error) { 79 wsURL := s.kubeClient.CoreV1().RESTClient().Post(). 80 Namespace(s.pod.Namespace). 81 Resource("pods"). 82 Name(s.pod.Name). 83 SubResource("exec"). 84 VersionedParams(&api.PodExecOptions{ 85 Stdin: true, 86 Stdout: true, 87 Stderr: true, 88 TTY: true, 89 Container: "build", 90 Command: []string{"sh", "-c", "bash || sh"}, 91 }, scheme.ParameterCodec).URL() 92 93 wsURL.Scheme = proxy.WebsocketProtocolFor(wsURL.Scheme) 94 return wsURL, nil 95 }