From c0902e26d2b6a453369e42e37d38799efaea9af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20P=C3=A9rez-Aradros=20Herce?= Date: Wed, 23 May 2018 11:19:50 +0200 Subject: [PATCH] Negotiate Docker API version New Docker versions have deprecated our hardcoded client API version (1.22), this change uses an API version negotiation mechanism to ensure compatibility. We should still upgrade to a newer client in the future, let's keep an eye on https://github.com/moby/moby/issues/33989 and do it once we have something we can vendor. --- CHANGELOG.asciidoc | 1 + libbeat/common/docker/client.go | 44 ++++++++++++++++++++++++++++++ libbeat/common/docker/watcher.go | 6 ++-- metricbeat/module/docker/docker.go | 3 +- 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 libbeat/common/docker/client.go 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 }