2018-02-05 16:05:59 -05:00
|
|
|
package client // import "github.com/docker/docker/client"
|
2016-09-06 14:46:37 -04:00
|
|
|
|
|
|
|
import (
|
2018-04-19 18:30:59 -04:00
|
|
|
"context"
|
2016-08-09 16:34:07 -04:00
|
|
|
"encoding/json"
|
2016-09-06 14:46:37 -04:00
|
|
|
"net/url"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/docker/docker/api/types"
|
2016-08-09 16:34:07 -04:00
|
|
|
"github.com/docker/docker/api/types/events"
|
2016-09-06 14:46:37 -04:00
|
|
|
"github.com/docker/docker/api/types/filters"
|
|
|
|
timetypes "github.com/docker/docker/api/types/time"
|
|
|
|
)
|
|
|
|
|
2016-08-09 16:34:07 -04:00
|
|
|
// Events returns a stream of events in the daemon. It's up to the caller to close the stream
|
|
|
|
// by cancelling the context. Once the stream has been completely read an io.EOF error will
|
|
|
|
// be sent over the error channel. If an error is sent all processing will be stopped. It's up
|
|
|
|
// to the caller to reopen the stream in the event of an error by reinvoking this method.
|
|
|
|
func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error) {
|
|
|
|
|
|
|
|
messages := make(chan events.Message)
|
|
|
|
errs := make(chan error, 1)
|
|
|
|
|
2016-12-15 13:07:27 -05:00
|
|
|
started := make(chan struct{})
|
2016-08-09 16:34:07 -04:00
|
|
|
go func() {
|
|
|
|
defer close(errs)
|
|
|
|
|
|
|
|
query, err := buildEventsQueryParams(cli.version, options)
|
|
|
|
if err != nil {
|
2016-12-15 13:07:27 -05:00
|
|
|
close(started)
|
2016-08-09 16:34:07 -04:00
|
|
|
errs <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := cli.get(ctx, "/events", query, nil)
|
|
|
|
if err != nil {
|
2016-12-15 13:07:27 -05:00
|
|
|
close(started)
|
2016-08-09 16:34:07 -04:00
|
|
|
errs <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer resp.body.Close()
|
|
|
|
|
|
|
|
decoder := json.NewDecoder(resp.body)
|
|
|
|
|
2016-12-15 13:07:27 -05:00
|
|
|
close(started)
|
2016-08-09 16:34:07 -04:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
errs <- ctx.Err()
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
var event events.Message
|
|
|
|
if err := decoder.Decode(&event); err != nil {
|
|
|
|
errs <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case messages <- event:
|
|
|
|
case <-ctx.Done():
|
|
|
|
errs <- ctx.Err()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
2016-12-15 13:07:27 -05:00
|
|
|
<-started
|
2016-08-09 16:34:07 -04:00
|
|
|
|
|
|
|
return messages, errs
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildEventsQueryParams(cliVersion string, options types.EventsOptions) (url.Values, error) {
|
2016-09-06 14:46:37 -04:00
|
|
|
query := url.Values{}
|
|
|
|
ref := time.Now()
|
|
|
|
|
|
|
|
if options.Since != "" {
|
|
|
|
ts, err := timetypes.GetTimestamp(options.Since, ref)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
query.Set("since", ts)
|
|
|
|
}
|
2016-08-09 16:34:07 -04:00
|
|
|
|
2016-09-06 14:46:37 -04:00
|
|
|
if options.Until != "" {
|
|
|
|
ts, err := timetypes.GetTimestamp(options.Until, ref)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
query.Set("until", ts)
|
|
|
|
}
|
2016-08-09 16:34:07 -04:00
|
|
|
|
2016-09-06 14:46:37 -04:00
|
|
|
if options.Filters.Len() > 0 {
|
2019-10-12 10:52:08 -04:00
|
|
|
//nolint:staticcheck // ignore SA1019 for old code
|
2016-08-09 16:34:07 -04:00
|
|
|
filterJSON, err := filters.ToParamWithVersion(cliVersion, options.Filters)
|
2016-09-06 14:46:37 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
query.Set("filters", filterJSON)
|
|
|
|
}
|
|
|
|
|
2016-08-09 16:34:07 -04:00
|
|
|
return query, nil
|
2016-09-06 14:46:37 -04:00
|
|
|
}
|