...
1
16
17 package remotecommand
18
19 import (
20 "encoding/json"
21 "errors"
22 "fmt"
23 "strconv"
24 "sync"
25
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/util/remotecommand"
28 "k8s.io/client-go/util/exec"
29 )
30
31
32
33
34 type streamProtocolV4 struct {
35 *streamProtocolV3
36 }
37
38 var _ streamProtocolHandler = &streamProtocolV4{}
39
40 func newStreamProtocolV4(options StreamOptions) streamProtocolHandler {
41 return &streamProtocolV4{
42 streamProtocolV3: newStreamProtocolV3(options).(*streamProtocolV3),
43 }
44 }
45
46 func (p *streamProtocolV4) createStreams(conn streamCreator) error {
47 return p.streamProtocolV3.createStreams(conn)
48 }
49
50 func (p *streamProtocolV4) handleResizes() {
51 p.streamProtocolV3.handleResizes()
52 }
53
54 func (p *streamProtocolV4) stream(conn streamCreator) error {
55 if err := p.createStreams(conn); err != nil {
56 return err
57 }
58
59
60
61 errorChan := watchErrorStream(p.errorStream, &errorDecoderV4{})
62
63 p.handleResizes()
64
65 p.copyStdin()
66
67 var wg sync.WaitGroup
68 p.copyStdout(&wg)
69 p.copyStderr(&wg)
70
71
72 wg.Wait()
73
74
75 return <-errorChan
76 }
77
78
79
80 type errorDecoderV4 struct{}
81
82 func (d *errorDecoderV4) decode(message []byte) error {
83 status := metav1.Status{}
84 err := json.Unmarshal(message, &status)
85 if err != nil {
86 return fmt.Errorf("error stream protocol error: %v in %q", err, string(message))
87 }
88 switch status.Status {
89 case metav1.StatusSuccess:
90 return nil
91 case metav1.StatusFailure:
92 if status.Reason == remotecommand.NonZeroExitCodeReason {
93 if status.Details == nil {
94 return errors.New("error stream protocol error: details must be set")
95 }
96 for i := range status.Details.Causes {
97 c := &status.Details.Causes[i]
98 if c.Type != remotecommand.ExitCodeCauseType {
99 continue
100 }
101
102 rc, err := strconv.ParseUint(c.Message, 10, 8)
103 if err != nil {
104 return fmt.Errorf("error stream protocol error: invalid exit code value %q", c.Message)
105 }
106 return exec.CodeExitError{
107 Err: fmt.Errorf("command terminated with exit code %d", rc),
108 Code: int(rc),
109 }
110 }
111
112 return fmt.Errorf("error stream protocol error: no %s cause given", remotecommand.ExitCodeCauseType)
113 }
114 default:
115 return errors.New("error stream protocol error: unknown error")
116 }
117
118 return fmt.Errorf(status.Message)
119 }
120
View as plain text