@@ -7,17 +7,48 @@ package docker
7
7
import (
8
8
"encoding/json"
9
9
"errors"
10
- "fmt"
11
10
"io"
12
11
"math"
13
12
"net"
14
13
"net/http"
15
14
"net/http/httputil"
15
+ "strconv"
16
16
"sync"
17
17
"sync/atomic"
18
18
"time"
19
19
)
20
20
21
+ // EventsOptions to filter events
22
+ // See https://docs.docker.com/engine/api/v1.41/#operation/SystemEvents for more details.
23
+ type EventsOptions struct {
24
+ // Show events created since this timestamp then stream new events.
25
+ Since string
26
+
27
+ // Show events created until this timestamp then stop streaming.
28
+ Until string
29
+
30
+ // Filter for events. For example:
31
+ // map[string][]string{"type": {"container"}, "event": {"start", "die"}}
32
+ // will return events when container was started and stopped or killed
33
+ //
34
+ // Available filters:
35
+ // config=<string> config name or ID
36
+ // container=<string> container name or ID
37
+ // daemon=<string> daemon name or ID
38
+ // event=<string> event type
39
+ // image=<string> image name or ID
40
+ // label=<string> image or container label
41
+ // network=<string> network name or ID
42
+ // node=<string> node ID
43
+ // plugin= plugin name or ID
44
+ // scope= local or swarm
45
+ // secret=<string> secret name or ID
46
+ // service=<string> service name or ID
47
+ // type=<string> container, image, volume, network, daemon, plugin, node, service, secret or config
48
+ // volume=<string> volume name
49
+ Filters map [string ][]string
50
+ }
51
+
21
52
// APIEvents represents events coming from the Docker API
22
53
// The fields in the Docker API changed in API version 1.22, and
23
54
// events for more than images and containers are now fired off.
@@ -93,9 +124,17 @@ var (
93
124
//
94
125
// The parameter is a channel through which events will be sent.
95
126
func (c * Client ) AddEventListener (listener chan <- * APIEvents ) error {
127
+ return c .AddEventListenerWithOptions (EventsOptions {}, listener )
128
+ }
129
+
130
+ // AddEventListener adds a new listener to container events in the Docker API.
131
+ // See https://docs.docker.com/engine/api/v1.41/#operation/SystemEvents for more details.
132
+ //
133
+ // The listener parameter is a channel through which events will be sent.
134
+ func (c * Client ) AddEventListenerWithOptions (options EventsOptions , listener chan <- * APIEvents ) error {
96
135
var err error
97
136
if ! c .eventMonitor .isEnabled () {
98
- err = c .eventMonitor .enableEventMonitoring (c )
137
+ err = c .eventMonitor .enableEventMonitoring (c , options )
99
138
if err != nil {
100
139
return err
101
140
}
@@ -165,15 +204,15 @@ func listenerExists(a chan<- *APIEvents, list *[]chan<- *APIEvents) bool {
165
204
return false
166
205
}
167
206
168
- func (eventState * eventMonitoringState ) enableEventMonitoring (c * Client ) error {
207
+ func (eventState * eventMonitoringState ) enableEventMonitoring (c * Client , opts EventsOptions ) error {
169
208
eventState .Lock ()
170
209
defer eventState .Unlock ()
171
210
if ! eventState .enabled {
172
211
eventState .enabled = true
173
212
atomic .StoreInt64 (& eventState .lastSeen , 0 )
174
213
eventState .C = make (chan * APIEvents , 100 )
175
214
eventState .errC = make (chan error , 1 )
176
- go eventState .monitorEvents (c )
215
+ go eventState .monitorEvents (c , opts )
177
216
}
178
217
return nil
179
218
}
@@ -193,7 +232,7 @@ func (eventState *eventMonitoringState) disableEventMonitoring() {
193
232
}
194
233
}
195
234
196
- func (eventState * eventMonitoringState ) monitorEvents (c * Client ) {
235
+ func (eventState * eventMonitoringState ) monitorEvents (c * Client , opts EventsOptions ) {
197
236
const (
198
237
noListenersTimeout = 5 * time .Second
199
238
noListenersInterval = 10 * time .Millisecond
@@ -213,7 +252,7 @@ func (eventState *eventMonitoringState) monitorEvents(c *Client) {
213
252
return
214
253
}
215
254
216
- if err = eventState .connectWithRetry (c ); err != nil {
255
+ if err = eventState .connectWithRetry (c , opts ); err != nil {
217
256
// terminate if connect failed
218
257
eventState .disableEventMonitoring ()
219
258
return
@@ -236,7 +275,7 @@ func (eventState *eventMonitoringState) monitorEvents(c *Client) {
236
275
eventState .disableEventMonitoring ()
237
276
return
238
277
} else if err != nil {
239
- defer func () { go eventState .monitorEvents (c ) }()
278
+ defer func () { go eventState .monitorEvents (c , opts ) }()
240
279
return
241
280
}
242
281
case <- timeout :
@@ -245,21 +284,21 @@ func (eventState *eventMonitoringState) monitorEvents(c *Client) {
245
284
}
246
285
}
247
286
248
- func (eventState * eventMonitoringState ) connectWithRetry (c * Client ) error {
287
+ func (eventState * eventMonitoringState ) connectWithRetry (c * Client , opts EventsOptions ) error {
249
288
var retries int
250
289
eventState .RLock ()
251
290
eventChan := eventState .C
252
291
errChan := eventState .errC
253
292
eventState .RUnlock ()
254
- err := c .eventHijack (atomic .LoadInt64 (& eventState .lastSeen ), eventChan , errChan )
293
+ err := c .eventHijack (opts , atomic .LoadInt64 (& eventState .lastSeen ), eventChan , errChan )
255
294
for ; err != nil && retries < maxMonitorConnRetries ; retries ++ {
256
295
waitTime := int64 (retryInitialWaitTime * math .Pow (2 , float64 (retries )))
257
296
time .Sleep (time .Duration (waitTime ) * time .Millisecond )
258
297
eventState .RLock ()
259
298
eventChan = eventState .C
260
299
errChan = eventState .errC
261
300
eventState .RUnlock ()
262
- err = c .eventHijack (atomic .LoadInt64 (& eventState .lastSeen ), eventChan , errChan )
301
+ err = c .eventHijack (opts , atomic .LoadInt64 (& eventState .lastSeen ), eventChan , errChan )
263
302
}
264
303
return err
265
304
}
@@ -304,11 +343,12 @@ func (eventState *eventMonitoringState) updateLastSeen(e *APIEvents) {
304
343
}
305
344
}
306
345
307
- func (c * Client ) eventHijack (startTime int64 , eventChan chan * APIEvents , errChan chan error ) error {
308
- uri := "/events"
346
+ func (c * Client ) eventHijack (opts EventsOptions , startTime int64 , eventChan chan * APIEvents , errChan chan error ) error {
347
+ // on reconnect override initial Since with last event seen time
309
348
if startTime != 0 {
310
- uri += fmt . Sprintf ( "?since=%d" , startTime )
349
+ opts . Since = strconv . FormatInt ( startTime , 10 )
311
350
}
351
+ uri := "/events?" + queryString (opts )
312
352
protocol := c .endpointURL .Scheme
313
353
address := c .endpointURL .Path
314
354
if protocol != "unix" && protocol != "npipe" {
0 commit comments