diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index ec90e42181fb..4ac478501ead 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -62,6 +62,7 @@ https://github.com/elastic/beats/compare/v6.2.3...master[Check the HEAD diff] - Fix map overwrite panics by cloning shared structs before doing the update. {pull}6947[6947] - Fix error if lz4 compression is used with the kafka output. {pull}7025[7025] - Preserve the event when source matching fails in `add_docker_metadata`. {pull}7133[7133] +- Negotiate Docker API version from our client instead of using a hardcoded one. {pull}7165[7165] *Auditbeat* diff --git a/libbeat/common/docker/client.go b/libbeat/common/docker/client.go new file mode 100644 index 000000000000..965fbb442c35 --- /dev/null +++ b/libbeat/common/docker/client.go @@ -0,0 +1,44 @@ +package docker + +import ( + "net/http" + + "github.com/elastic/beats/libbeat/logp" + + "github.com/docker/docker/api" + "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/client" + "golang.org/x/net/context" +) + +// Select Docker API version +const dockerAPIVersion = api.DefaultVersion + +// NewClient builds and returns a new Docker client +// It uses version 1.26 by default, and negotiates it with the server so it is downgraded if 1.26 is too high +func NewClient(host string, httpClient *http.Client, httpHeaders map[string]string) (*client.Client, error) { + c, err := client.NewClient(host, dockerAPIVersion, httpClient, nil) + if err != nil { + return c, err + } + + logp.Debug("docker", "Negotiating client version") + ping, err := c.Ping(context.Background()) + if err != nil { + logp.Debug("docker", "Failed to perform ping: %s", err) + } + + // try the latest version before versioning headers existed + if ping.APIVersion == "" { + ping.APIVersion = "1.24" + } + + // if server version is lower than the client version, downgrade + if versions.LessThan(ping.APIVersion, dockerAPIVersion) { + c.UpdateClientVersion(ping.APIVersion) + } + + logp.Debug("docker", "Client version set to %s", c.ClientVersion()) + + return c, nil +} diff --git a/libbeat/common/docker/watcher.go b/libbeat/common/docker/watcher.go index 02c4a0cb11cc..5c2e03fea4cc 100644 --- a/libbeat/common/docker/watcher.go +++ b/libbeat/common/docker/watcher.go @@ -9,7 +9,6 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/events" "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/client" "github.com/docker/go-connections/tlsconfig" "golang.org/x/net/context" @@ -19,8 +18,7 @@ import ( // Select Docker API version const ( - dockerAPIVersion = "1.22" - shortIDLen = 12 + shortIDLen = 12 ) // Watcher reads docker events and keeps a list of known containers @@ -106,7 +104,7 @@ func NewWatcher(host string, tls *TLSConfig, storeShortID bool) (Watcher, error) } } - client, err := client.NewClient(host, dockerAPIVersion, httpClient, nil) + client, err := NewClient(host, httpClient, nil) if err != nil { return nil, err } diff --git a/metricbeat/module/docker/docker.go b/metricbeat/module/docker/docker.go index 1023409419cb..02408c365430 100644 --- a/metricbeat/module/docker/docker.go +++ b/metricbeat/module/docker/docker.go @@ -11,6 +11,7 @@ import ( "github.com/docker/docker/client" "github.com/docker/go-connections/tlsconfig" + "github.com/elastic/beats/libbeat/common/docker" "github.com/elastic/beats/metricbeat/mb" "github.com/elastic/beats/metricbeat/mb/parse" ) @@ -67,7 +68,7 @@ func NewDockerClient(endpoint string, config Config) (*client.Client, error) { } } - client, err := client.NewClient(endpoint, dockerAPIVersion, httpClient, nil) + client, err := docker.NewClient(endpoint, httpClient, nil) if err != nil { return nil, err }