Skip to content

Commit ca25cc2

Browse files
authored
hiveproxy: handle errors during connection setup (#599)
* hiveproxy: handle errors during connection setup This fixes a panic in internal/libdocker, which could occur when hive was interrupted while setting up the proxy. * hiveproxy: rename executable
1 parent 2b7393f commit ca25cc2

File tree

4 files changed

+51
-23
lines changed

4 files changed

+51
-23
lines changed

hiveproxy/Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ RUN go mod download
1010

1111
# Now build the proxy executable.
1212
ADD . /source
13-
RUN go build -o hive-proxy ./tool
13+
RUN go build -o /bin/hiveproxy ./tool
1414

1515
# Pull the executable into a fresh image.
1616
FROM alpine:latest
17-
COPY --from=builder /source/hive-proxy .
17+
COPY --from=builder /bin/hiveproxy .
1818
EXPOSE 8081/tcp
19-
ENTRYPOINT ./hive-proxy --addr :8081
19+
ENTRYPOINT ./hiveproxy --addr :8081

hiveproxy/proxy.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,18 @@ func (p *Proxy) launchRPC(stream net.Conn) {
117117
// to the backend.
118118
//
119119
// All communication with the backend runs over the given r,w streams.
120-
func RunFrontend(r io.Reader, w io.WriteCloser, listener net.Listener) *Proxy {
121-
mux, _ := yamux.Client(rwCombo{r, w}, muxcfg)
120+
func RunFrontend(r io.Reader, w io.WriteCloser, listener net.Listener) (*Proxy, error) {
122121
p := newProxy(true)
122+
mux, err := yamux.Client(rwCombo{r, w}, muxcfg)
123+
if err != nil {
124+
return nil, err
125+
}
123126

124127
// Launch RPC handler.
125128
rpcConn, err := mux.Open()
126129
if err != nil {
127-
panic(err)
130+
mux.Close()
131+
return nil, err
128132
}
129133
p.launchRPC(rpcConn)
130134
p.rpc.RegisterName("proxy", new(proxyFunctions))
@@ -144,28 +148,32 @@ func RunFrontend(r io.Reader, w io.WriteCloser, listener net.Listener) *Proxy {
144148
Transport: transport,
145149
}
146150
go p.serve(listener)
147-
return p
151+
return p, nil
148152
}
149153

150154
// RunBackend starts the proxy backend, i.e. the side which handles HTTP requests proxied
151155
// by the frontend.
152156
//
153157
// All communication with the frontend runs over the given r,w streams.
154-
func RunBackend(r io.Reader, w io.WriteCloser, h http.Handler) *Proxy {
155-
mux, _ := yamux.Server(rwCombo{r, w}, muxcfg)
158+
func RunBackend(r io.Reader, w io.WriteCloser, h http.Handler) (*Proxy, error) {
156159
p := newProxy(false)
160+
mux, err := yamux.Server(rwCombo{r, w}, muxcfg)
161+
if err != nil {
162+
return nil, err
163+
}
157164

158165
// Start RPC client.
159166
rpcConn, err := mux.Accept()
160167
if err != nil {
161-
panic(err)
168+
mux.Close()
169+
return nil, err
162170
}
163171
p.launchRPC(rpcConn)
164172

165173
// Start HTTP server.
166174
p.httpsrv.Handler = h
167175
go p.serve(mux)
168-
return p
176+
return p, nil
169177
}
170178

171179
type rwCombo struct {

hiveproxy/proxy_test.go

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestProxyCheckLive(t *testing.T) {
4040
defer tl.Close()
4141

4242
// Run CheckLive on the backend side.
43-
addr := tl.l.Addr().(*net.TCPAddr)
43+
addr := tl.lis.Addr().(*net.TCPAddr)
4444
if err := p.back.CheckLive(context.Background(), addr); err != nil {
4545
t.Fatal("CheckLive did not work:", err)
4646
}
@@ -80,15 +80,27 @@ func runProxyPair(t *testing.T, h http.Handler) proxyPair {
8080
t.Fatal(err)
8181
}
8282
p.lis = l
83-
frontStarted := make(chan struct{})
83+
frontStarted := make(chan error, 1)
8484
go func() {
85-
p.front = RunFrontend(cr, cw, l)
86-
close(frontStarted)
85+
var err error
86+
p.front, err = RunFrontend(cr, cw, l)
87+
frontStarted <- err
8788
}()
8889

8990
// Run the backend.
90-
p.back = RunBackend(sr, sw, h)
91-
<-frontStarted
91+
p.back, err = RunBackend(sr, sw, h)
92+
if err != nil {
93+
<-frontStarted
94+
if p.front != nil {
95+
p.front.Close()
96+
}
97+
t.Fatal(err)
98+
}
99+
100+
if err := <-frontStarted; err != nil {
101+
p.back.Close()
102+
t.Fatal(err)
103+
}
92104
return p
93105
}
94106

@@ -98,30 +110,30 @@ func (p proxyPair) close() {
98110
}
99111

100112
type testListener struct {
101-
l net.Listener
102-
wg sync.WaitGroup
113+
lis net.Listener
114+
wg sync.WaitGroup
103115
}
104116

105117
func runTestListener(addr string) (*testListener, error) {
106118
l, err := net.Listen("tcp", addr)
107119
if err != nil {
108120
return nil, err
109121
}
110-
tl := &testListener{l: l}
122+
tl := &testListener{lis: l}
111123
tl.wg.Add(1)
112124
go tl.acceptLoop()
113125
return tl, nil
114126
}
115127

116128
func (tl *testListener) Close() {
117-
tl.l.Close()
129+
tl.lis.Close()
118130
tl.wg.Wait()
119131
}
120132

121133
func (tl *testListener) acceptLoop() {
122134
defer tl.wg.Done()
123135
for {
124-
c, err := tl.l.Accept()
136+
c, err := tl.lis.Accept()
125137
if err != nil {
126138
return
127139
}

internal/libdocker/proxy.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,15 @@ func (cb *ContainerBackend) ServeAPI(ctx context.Context, h http.Handler) (libhi
3535
return nil, err
3636
}
3737

38-
proxy := hiveproxy.RunBackend(outR, inW, h)
38+
proxy, err := hiveproxy.RunBackend(outR, inW, h)
39+
if err != nil {
40+
cb.DeleteContainer(id)
41+
return nil, err
42+
}
43+
44+
// Register proxy in ContainerBackend, so it can be used for CheckLive.
45+
cb.proxy = proxy
46+
3947
srv := &proxyContainer{
4048
cb: cb,
4149
containerID: id,

0 commit comments

Comments
 (0)