Skip to content

Commit

Permalink
Use docker error message to negotiate api version as a fallback (#99)
Browse files Browse the repository at this point in the history
* Use docker error message to negotiate api version as a fallback

* Add comments describing regex

* Use regex.MustCompile

* Hoist regex outside function

* Flatten logic

* Update changelog
  • Loading branch information
laverya committed Jan 25, 2018
1 parent fd7cc5c commit 830dbef
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
3 changes: 2 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@
* Updated docker client library to latest
* Docker client now negotiates a version

0.10.1 /2018-01-08
0.10.1 /2018-01-24
* Patch CVE-2017-17512 sensible-utils-0.0.9
* Added fallback logic for Docker client version negotiation with Docker server API versions < 1.24
38 changes: 38 additions & 0 deletions pkg/plugins/docker/producers/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package producers
import (
"context"
"errors"
"log"
"regexp"

"github.com/docker/docker/api/types"
docker "github.com/docker/docker/client"
Expand All @@ -12,8 +14,44 @@ type Docker struct {
client *docker.Client
}

// this matches server version within error strings like this:
// `Error response from daemon: client is newer than server (client API version: 1.24, server API version: 1.19)`
var dockerErrorVersionRegexp *regexp.Regexp = regexp.MustCompile(`server API version:\s*(\d\.\d+)\s*\)`)

func New(client *docker.Client) *Docker {
client.NegotiateAPIVersion(context.Background())

if client.ClientVersion() != "1.24" {
return &Docker{client}
}

// there is a possibility that negotiation failed as this is the default value for that case
// so we send a ping and check ourselves
ping, _ := client.Ping(context.Background())
if ping.APIVersion != "" {
return &Docker{client}
}

// negotiation failed, so we get to fake it
log.Printf("Docker API version negotiation failed. Attempting fallback...")
_, err := client.ServerVersion(context.Background())

if err == nil {
// ironically, this is actually a bit of a failure
return &Docker{client}
}

matches := dockerErrorVersionRegexp.FindStringSubmatch(err.Error())

if len(matches) < 2 {
log.Printf("Docker API version negotiation fallback failed")
} else {
log.Printf("Fallback API version detection: %+v", matches[1])
var fakePing types.Ping
fakePing.APIVersion = matches[1]
client.NegotiateAPIVersionPing(fakePing)
}

return &Docker{client}
}

Expand Down

0 comments on commit 830dbef

Please sign in to comment.