@@ -17,6 +17,7 @@ import (
17
17
"bufio"
18
18
"context"
19
19
"fmt"
20
+ "io/ioutil"
20
21
"net"
21
22
"strings"
22
23
"time"
@@ -25,21 +26,64 @@ import (
25
26
"github.com/sirupsen/logrus"
26
27
)
27
28
28
- type Timeout struct {
29
+ type config struct {
30
+ logger logrus.FieldLogger
29
31
DialTimeout time.Duration
30
32
RetryTimeout time.Duration
31
33
RetryInterval time.Duration
32
34
ConnectMsgTimeout time.Duration
33
35
AckMsgTimeout time.Duration
34
36
}
35
37
36
- func DefaultTimeouts () Timeout {
37
- return Timeout {
38
+ func defaultConfig () config {
39
+ noop := logrus .New ()
40
+ noop .Out = ioutil .Discard
41
+
42
+ return config {
38
43
DialTimeout : 100 * time .Millisecond ,
39
44
RetryTimeout : 20 * time .Second ,
40
45
RetryInterval : 100 * time .Millisecond ,
41
46
ConnectMsgTimeout : 100 * time .Millisecond ,
42
47
AckMsgTimeout : 1 * time .Second ,
48
+ logger : noop ,
49
+ }
50
+ }
51
+
52
+ type DialOption func (c * config )
53
+
54
+ func WithDialTimeout (d time.Duration ) DialOption {
55
+ return func (c * config ) {
56
+ c .DialTimeout = d
57
+ }
58
+ }
59
+
60
+ func WithRetryTimeout (d time.Duration ) DialOption {
61
+ return func (c * config ) {
62
+ c .RetryTimeout = d
63
+ }
64
+ }
65
+
66
+ func WithRetryInterval (d time.Duration ) DialOption {
67
+ return func (c * config ) {
68
+ c .RetryInterval = d
69
+ }
70
+ }
71
+
72
+ func WithConnectionMsgTimeout (d time.Duration ) DialOption {
73
+ return func (c * config ) {
74
+ c .ConnectMsgTimeout = d
75
+ }
76
+ }
77
+
78
+ func WithAckMsgTimeout (d time.Duration ) DialOption {
79
+ return func (c * config ) {
80
+ c .AckMsgTimeout = d
81
+ }
82
+ }
83
+
84
+ func WithLogger (logger logrus.FieldLogger ) DialOption {
85
+ return func (c * config ) {
86
+ c .logger = logger
43
87
}
44
88
}
45
89
@@ -48,20 +92,31 @@ func DefaultTimeouts() Timeout {
48
92
// It will retry connect attempts if a temporary error is encountered up to a fixed
49
93
// timeout or the provided request is canceled.
50
94
//
51
- // udsPath specifies the file system path of the UNIX domain socket.
95
+ // path specifies the file system path of the UNIX domain socket.
52
96
//
53
97
// port will be used in the connect message to the firecracker vsock.
54
- func Dial (ctx context.Context , logger * logrus.Entry , udsPath string , port uint32 ) (net.Conn , error ) {
55
- return DialTimeout (ctx , logger , udsPath , port , DefaultTimeouts ())
98
+ func DialContext (ctx context.Context , path string , port uint32 , opts ... DialOption ) (net.Conn , error ) {
99
+ t := defaultConfig ()
100
+ for _ , o := range opts {
101
+ o (& t )
102
+ }
103
+
104
+ return dial (ctx , path , port , t )
56
105
}
57
106
58
- // DialTimeout acts like Dial but takes a timeout .
107
+ // Dial connects to the Firecracker host-side vsock at the provided unix path and port .
59
108
//
60
- // See func Dial for a description of the udsPath and port parameters.
61
- func DialTimeout (ctx context.Context , logger * logrus.Entry , udsPath string , port uint32 , timeout Timeout ) (net.Conn , error ) {
62
- ticker := time .NewTicker (timeout .RetryInterval )
109
+ // See func Dial for a description of the path and port parameters.
110
+ func Dial (path string , port uint32 , opts ... DialOption ) (net.Conn , error ) {
111
+ return DialContext (context .Background (), path , port , opts ... )
112
+ }
113
+
114
+ func dial (ctx context.Context , udsPath string , port uint32 , c config ) (net.Conn , error ) {
115
+ ticker := time .NewTicker (c .RetryInterval )
63
116
defer ticker .Stop ()
64
117
118
+ logger := c .logger
119
+
65
120
tickerCh := ticker .C
66
121
var attemptCount int
67
122
for {
@@ -72,7 +127,7 @@ func DialTimeout(ctx context.Context, logger *logrus.Entry, udsPath string, port
72
127
case <- ctx .Done ():
73
128
return nil , ctx .Err ()
74
129
case <- tickerCh :
75
- conn , err := tryConnect (logger , udsPath , port , timeout )
130
+ conn , err := tryConnect (logger , udsPath , port , c )
76
131
if isTemporaryNetErr (err ) {
77
132
err = errors .Wrap (err , "temporary vsock dial failure" )
78
133
logger .WithError (err ).Debug ()
@@ -98,10 +153,10 @@ func connectMsg(port uint32) string {
98
153
99
154
// tryConnect attempts to dial a guest vsock listener at the provided host-side
100
155
// unix socket and provided guest-listener port.
101
- func tryConnect (logger * logrus.Entry , udsPath string , port uint32 , timeout Timeout ) (net.Conn , error ) {
102
- conn , err := net .DialTimeout ("unix" , udsPath , timeout .DialTimeout )
156
+ func tryConnect (logger * logrus.Entry , udsPath string , port uint32 , c config ) (net.Conn , error ) {
157
+ conn , err := net .DialTimeout ("unix" , udsPath , c .DialTimeout )
103
158
if err != nil {
104
- return nil , errors .Wrapf (err , "failed to dial %q within %s" , udsPath , timeout .DialTimeout )
159
+ return nil , errors .Wrapf (err , "failed to dial %q within %s" , udsPath , c .DialTimeout )
105
160
}
106
161
107
162
defer func () {
@@ -115,17 +170,17 @@ func tryConnect(logger *logrus.Entry, udsPath string, port uint32, timeout Timeo
115
170
}()
116
171
117
172
msg := connectMsg (port )
118
- err = tryConnWrite (conn , msg , timeout .ConnectMsgTimeout )
173
+ err = tryConnWrite (conn , msg , c .ConnectMsgTimeout )
119
174
if err != nil {
120
175
return nil , connectMsgError {
121
- cause : errors .Wrapf (err , `failed to write %q within %s` , msg , timeout .ConnectMsgTimeout ),
176
+ cause : errors .Wrapf (err , `failed to write %q within %s` , msg , c .ConnectMsgTimeout ),
122
177
}
123
178
}
124
179
125
- line , err := tryConnReadUntil (conn , '\n' , timeout .AckMsgTimeout )
180
+ line , err := tryConnReadUntil (conn , '\n' , c .AckMsgTimeout )
126
181
if err != nil {
127
182
return nil , ackError {
128
- cause : errors .Wrapf (err , `failed to read "OK <port>" within %s` , timeout .AckMsgTimeout ),
183
+ cause : errors .Wrapf (err , `failed to read "OK <port>" within %s` , c .AckMsgTimeout ),
129
184
}
130
185
}
131
186
0 commit comments