From 2a345ffa9e6a99a6eea367571868bd0d02c5b43f Mon Sep 17 00:00:00 2001 From: Francisco Souza Date: Wed, 30 Jul 2014 15:18:42 -0300 Subject: [PATCH] third_party: update go-dockerclient math.MaxInt64 represents 8 exabytes, which is a good limit for memory. Also, this is the type used by Docker, so it's not possible to get any value bigger than math.MaxInt64 as memory limit (both ram and swap) on a Docker container. Relevant discussion at #589 (more precisely, https://github.com/GoogleCloudPlatform/kubernetes/pull/589#issuecomment-50640605). --- pkg/kubelet/kubelet.go | 2 +- .../github.com/fsouza/go-dockerclient/AUTHORS | 4 + .../fsouza/go-dockerclient/README.markdown | 44 +-- .../fsouza/go-dockerclient/client.go | 52 +-- .../fsouza/go-dockerclient/client_test.go | 9 +- .../fsouza/go-dockerclient/container.go | 6 +- .../fsouza/go-dockerclient/container_test.go | 84 ++++- .../github.com/fsouza/go-dockerclient/env.go | 137 +++++++ .../fsouza/go-dockerclient/env_test.go | 349 ++++++++++++++++++ .../fsouza/go-dockerclient/event_test.go | 2 +- .../fsouza/go-dockerclient/image_test.go | 2 +- .../github.com/fsouza/go-dockerclient/misc.go | 19 +- .../fsouza/go-dockerclient/misc_test.go | 4 +- .../fsouza/go-dockerclient/testing/server.go | 17 +- .../go-dockerclient/testing/server_test.go | 25 +- .../fsouza/go-dockerclient/utils/stdcopy.go | 5 - 16 files changed, 658 insertions(+), 103 deletions(-) create mode 100644 third_party/src/github.com/fsouza/go-dockerclient/env.go create mode 100644 third_party/src/github.com/fsouza/go-dockerclient/env_test.go diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index a756b8a1b954b..abd2ace18cf71 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -289,7 +289,7 @@ func (kl *Kubelet) runContainer(pod *Pod, container *api.Container, podVolumes v ExposedPorts: exposedPorts, Hostname: container.Name, Image: container.Image, - Memory: uint64(container.Memory), + Memory: int64(container.Memory), CpuShares: int64(milliCPUToShares(container.CPU)), Volumes: volumes, WorkingDir: container.WorkingDir, diff --git a/third_party/src/github.com/fsouza/go-dockerclient/AUTHORS b/third_party/src/github.com/fsouza/go-dockerclient/AUTHORS index d42a14a8324d0..98ff17b948a47 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/AUTHORS +++ b/third_party/src/github.com/fsouza/go-dockerclient/AUTHORS @@ -1,5 +1,6 @@ # This is the official list of go-dockerclient authors for copyright purposes. +Andreas Jaekle Andrews Medina Andy Goldstein Ben McCann @@ -8,6 +9,7 @@ Cheah Chu Yeow cheneydeng Ed Eric Anderson +Fabio Rehm Flavia Missi Francisco Souza Jari Kolehmainen @@ -15,6 +17,8 @@ Jason Wilder Jean-Baptiste Dalido Jeff Mitchell Jeffrey Hulten +Johan Euphrosine +Karan Misra Lucas Clemente Omeid Matten Paul Morie diff --git a/third_party/src/github.com/fsouza/go-dockerclient/README.markdown b/third_party/src/github.com/fsouza/go-dockerclient/README.markdown index 7b4e959e0a235..0b7e83c63daf3 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/README.markdown +++ b/third_party/src/github.com/fsouza/go-dockerclient/README.markdown @@ -11,27 +11,29 @@ For more details, check the [remote API documentation](http://docs.docker.io/en/ ## Example - package main - - import ( - "fmt" - "github.com/fsouza/go-dockerclient" - ) - - func main() { - endpoint := "unix:///var/run/docker.sock" - client, _ := docker.NewClient(endpoint) - imgs, _ := client.ListImages(true) - for _, img := range imgs { - fmt.Println("ID: ", img.ID) - fmt.Println("RepoTags: ", img.RepoTags) - fmt.Println("Created: ", img.Created) - fmt.Println("Size: ", img.Size) - fmt.Println("VirtualSize: ", img.VirtualSize) - fmt.Println("ParentId: ", img.ParentId) - fmt.Println("Repository: ", img.Repository) - } - } +```go +package main + +import ( + "fmt" + "github.com/fsouza/go-dockerclient" +) + +func main() { + endpoint := "unix:///var/run/docker.sock" + client, _ := docker.NewClient(endpoint) + imgs, _ := client.ListImages(true) + for _, img := range imgs { + fmt.Println("ID: ", img.ID) + fmt.Println("RepoTags: ", img.RepoTags) + fmt.Println("Created: ", img.Created) + fmt.Println("Size: ", img.Size) + fmt.Println("VirtualSize: ", img.VirtualSize) + fmt.Println("ParentId: ", img.ParentId) + fmt.Println("Repository: ", img.Repository) + } +} +``` ## Developing diff --git a/third_party/src/github.com/fsouza/go-dockerclient/client.go b/third_party/src/github.com/fsouza/go-dockerclient/client.go index 681b7bf7835ad..74c15072ec43c 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/client.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/client.go @@ -21,7 +21,6 @@ import ( "reflect" "strconv" "strings" - "sync" "github.com/fsouza/go-dockerclient/utils" ) @@ -113,11 +112,11 @@ func (version ApiVersion) compare(other ApiVersion) int { // interaction with the API. type Client struct { SkipServerVersionCheck bool + HTTPClient *http.Client endpoint string endpointURL *url.URL eventMonitor *eventMonitoringState - client *http.Client requestedApiVersion ApiVersion serverApiVersion ApiVersion expectedApiVersion ApiVersion @@ -142,7 +141,6 @@ func NewVersionedClient(endpoint string, apiVersionString string) (*Client, erro if err != nil { return nil, err } - var requestedApiVersion ApiVersion if strings.Contains(apiVersionString, ".") { requestedApiVersion, err = NewApiVersion(apiVersionString) @@ -150,11 +148,10 @@ func NewVersionedClient(endpoint string, apiVersionString string) (*Client, erro return nil, err } } - return &Client{ + HTTPClient: http.DefaultClient, endpoint: endpoint, endpointURL: u, - client: http.DefaultClient, eventMonitor: new(eventMonitoringState), requestedApiVersion: requestedApiVersion, }, nil @@ -177,29 +174,6 @@ func (c *Client) checkApiVersion() error { return nil } -func parseApiVersionString(input string) (version uint16, err error) { - version = 0 - - if !strings.Contains(input, ".") { - return 0, fmt.Errorf("Unable to parse version '%s'", input) - } - - arr := strings.Split(input, ".") - - major, err := strconv.Atoi(arr[0]) - if err != nil { - return version, err - } - - minor, err := strconv.Atoi(arr[1]) - if err != nil { - return version, err - } - - version = uint16(major)<<8 | uint16(minor) - return version, nil -} - // Ping pings the docker server // // See http://goo.gl/stJENm for more details. @@ -223,13 +197,11 @@ func (c *Client) getServerApiVersionString() (version string, err error) { if status != http.StatusOK { return "", fmt.Errorf("Received unexpected status %d while trying to retrieve the server version", status) } - var versionResponse map[string]string err = json.Unmarshal(body, &versionResponse) if err != nil { return "", err } - version = versionResponse["ApiVersion"] return version, nil } @@ -243,14 +215,12 @@ func (c *Client) do(method, path string, data interface{}) ([]byte, int, error) } params = bytes.NewBuffer(buf) } - if path != "/version" && !c.SkipServerVersionCheck && c.expectedApiVersion == nil { err := c.checkApiVersion() if err != nil { return nil, -1, err } } - req, err := http.NewRequest(method, c.getURL(path), params) if err != nil { return nil, -1, err @@ -277,7 +247,7 @@ func (c *Client) do(method, path string, data interface{}) ([]byte, int, error) } defer clientconn.Close() } else { - resp, err = c.client.Do(req) + resp, err = c.HTTPClient.Do(req) } if err != nil { if strings.Contains(err.Error(), "connection refused") { @@ -335,7 +305,7 @@ func (c *Client) stream(method, path string, setRawTerminal bool, headers map[st resp, err = clientconn.Do(req) defer clientconn.Close() } else { - resp, err = c.client.Do(req) + resp, err = c.HTTPClient.Do(req) } if err != nil { if strings.Contains(err.Error(), "connection refused") { @@ -418,10 +388,10 @@ func (c *Client) hijack(method, path string, success chan struct{}, setRawTermin <-success } rwc, br := clientconn.Hijack() - var wg sync.WaitGroup - wg.Add(2) errs := make(chan error, 2) + exit := make(chan bool) go func() { + defer close(exit) var err error if setRawTerminal { _, err = io.Copy(stdout, br) @@ -429,7 +399,6 @@ func (c *Client) hijack(method, path string, success chan struct{}, setRawTermin _, err = utils.StdCopy(stdout, stderr, br) } errs <- err - wg.Done() }() go func() { var err error @@ -440,14 +409,9 @@ func (c *Client) hijack(method, path string, success chan struct{}, setRawTermin CloseWrite() error }).CloseWrite() errs <- err - wg.Done() }() - wg.Wait() - close(errs) - if err := <-errs; err != nil { - return err - } - return nil + <-exit + return <-errs } func (c *Client) getURL(path string) string { diff --git a/third_party/src/github.com/fsouza/go-dockerclient/client_test.go b/third_party/src/github.com/fsouza/go-dockerclient/client_test.go index 53edd6c24c013..e623263f90ff1 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/client_test.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/client_test.go @@ -24,10 +24,9 @@ func TestNewAPIClient(t *testing.T) { if client.endpoint != endpoint { t.Errorf("Expected endpoint %s. Got %s.", endpoint, client.endpoint) } - if client.client != http.DefaultClient { - t.Errorf("Expected http.Client %#v. Got %#v.", http.DefaultClient, client.client) + if client.HTTPClient != http.DefaultClient { + t.Errorf("Expected http.Client %#v. Got %#v.", http.DefaultClient, client.HTTPClient) } - // test unix socket endpoints endpoint = "unix:///var/run/docker.sock" client, err = NewClient(endpoint) @@ -54,8 +53,8 @@ func TestNewVersionedClient(t *testing.T) { if client.endpoint != endpoint { t.Errorf("Expected endpoint %s. Got %s.", endpoint, client.endpoint) } - if client.client != http.DefaultClient { - t.Errorf("Expected http.Client %#v. Got %#v.", http.DefaultClient, client.client) + if client.HTTPClient != http.DefaultClient { + t.Errorf("Expected http.Client %#v. Got %#v.", http.DefaultClient, client.HTTPClient) } if reqVersion := client.requestedApiVersion.String(); reqVersion != "1.12" { t.Errorf("Wrong requestApiVersion. Want %q. Got %q.", "1.12", reqVersion) diff --git a/third_party/src/github.com/fsouza/go-dockerclient/container.go b/third_party/src/github.com/fsouza/go-dockerclient/container.go index 25e1fad5f6747..ab2c873e80d0a 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/container.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/container.go @@ -158,8 +158,8 @@ type Config struct { Hostname string Domainname string User string - Memory uint64 - MemorySwap uint64 + Memory int64 + MemorySwap int64 CpuShares int64 AttachStdin bool AttachStdout bool @@ -297,7 +297,7 @@ type HostConfig struct { NetworkMode string } -// StartContainer starts a container, returning an errror in case of failure. +// StartContainer starts a container, returning an error in case of failure. // // See http://goo.gl/y5GZlE for more details. func (c *Client) StartContainer(id string, hostConfig *HostConfig) error { diff --git a/third_party/src/github.com/fsouza/go-dockerclient/container_test.go b/third_party/src/github.com/fsouza/go-dockerclient/container_test.go index fbe9d1f74b49a..c027c92c4e047 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/container_test.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/container_test.go @@ -225,6 +225,88 @@ func TestInspectContainer(t *testing.T) { } } +func TestInspectContainerNegativeSwap(t *testing.T) { + jsonContainer := `{ + "Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2", + "Created": "2013-05-07T14:51:42.087658+02:00", + "Path": "date", + "Args": [], + "Config": { + "Hostname": "4fa6e0f0c678", + "User": "", + "Memory": 17179869184, + "MemorySwap": -1, + "AttachStdin": false, + "AttachStdout": true, + "AttachStderr": true, + "PortSpecs": null, + "Tty": false, + "OpenStdin": false, + "StdinOnce": false, + "Env": null, + "Cmd": [ + "date" + ], + "Image": "base", + "Volumes": {}, + "VolumesFrom": "" + }, + "State": { + "Running": false, + "Pid": 0, + "ExitCode": 0, + "StartedAt": "2013-05-07T14:51:42.087658+02:00", + "Ghost": false + }, + "Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", + "NetworkSettings": { + "IpAddress": "", + "IpPrefixLen": 0, + "Gateway": "", + "Bridge": "", + "PortMapping": null + }, + "SysInitPath": "/home/kitty/go/src/github.com/dotcloud/docker/bin/docker", + "ResolvConfPath": "/etc/resolv.conf", + "Volumes": {}, + "HostConfig": { + "Binds": null, + "ContainerIDFile": "", + "LxcConf": [], + "Privileged": false, + "PortBindings": { + "80/tcp": [ + { + "HostIp": "0.0.0.0", + "HostPort": "49153" + } + ] + }, + "Links": null, + "PublishAllPorts": false + } +}` + var expected Container + err := json.Unmarshal([]byte(jsonContainer), &expected) + if err != nil { + t.Fatal(err) + } + fakeRT := &FakeRoundTripper{message: jsonContainer, status: http.StatusOK} + client := newTestClient(fakeRT) + id := "4fa6e0f0c678" + container, err := client.InspectContainer(id) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(*container, expected) { + t.Errorf("InspectContainer(%q): Expected %#v. Got %#v.", id, expected, container) + } + expectedURL, _ := url.Parse(client.getURL("/containers/4fa6e0f0c678/json")) + if gotPath := fakeRT.requests[0].URL.Path; gotPath != expectedURL.Path { + t.Errorf("InspectContainer(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath) + } +} + func TestInspectContainerFailure(t *testing.T) { client := newTestClient(&FakeRoundTripper{message: "server error", status: 500}) expected := Error{Status: 500, Message: "server error"} @@ -1184,9 +1266,9 @@ func TestExportContainerViaUnixSocket(t *testing.T) { endpoint := "unix://" + tempSocket u, _ := parseEndpoint(endpoint) client := Client{ + HTTPClient: http.DefaultClient, endpoint: endpoint, endpointURL: u, - client: http.DefaultClient, SkipServerVersionCheck: true, } listening := make(chan string) diff --git a/third_party/src/github.com/fsouza/go-dockerclient/env.go b/third_party/src/github.com/fsouza/go-dockerclient/env.go new file mode 100644 index 0000000000000..c5ecb2b4ba021 --- /dev/null +++ b/third_party/src/github.com/fsouza/go-dockerclient/env.go @@ -0,0 +1,137 @@ +// Copyright 2014 Docker authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package docker + +import ( + "encoding/json" + "fmt" + "io" + "strconv" + "strings" +) + +type Env []string + +func (env *Env) Get(key string) (value string) { + return env.Map()[key] +} + +func (env *Env) Exists(key string) bool { + _, exists := env.Map()[key] + return exists +} + +func (env *Env) GetBool(key string) (value bool) { + s := strings.ToLower(strings.Trim(env.Get(key), " \t")) + if s == "" || s == "0" || s == "no" || s == "false" || s == "none" { + return false + } + return true +} + +func (env *Env) SetBool(key string, value bool) { + if value { + env.Set(key, "1") + } else { + env.Set(key, "0") + } +} + +func (env *Env) GetInt(key string) int { + return int(env.GetInt64(key)) +} + +func (env *Env) SetInt(key string, value int) { + env.Set(key, strconv.Itoa(value)) +} + +func (env *Env) GetInt64(key string) int64 { + s := strings.Trim(env.Get(key), " \t") + val, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return -1 + } + return val +} + +func (env *Env) SetInt64(key string, value int64) { + env.Set(key, strconv.FormatInt(value, 10)) +} + +func (env *Env) GetJson(key string, iface interface{}) error { + sval := env.Get(key) + if sval == "" { + return nil + } + return json.Unmarshal([]byte(sval), iface) +} + +func (env *Env) SetJson(key string, value interface{}) error { + sval, err := json.Marshal(value) + if err != nil { + return err + } + env.Set(key, string(sval)) + return nil +} + +func (env *Env) GetList(key string) []string { + sval := env.Get(key) + if sval == "" { + return nil + } + var l []string + if err := json.Unmarshal([]byte(sval), &l); err != nil { + l = append(l, sval) + } + return l +} + +func (env *Env) SetList(key string, value []string) error { + return env.SetJson(key, value) +} + +func (env *Env) Set(key, value string) { + *env = append(*env, key+"="+value) +} + +// Decode decodes `src` as a json dictionary, and adds each decoded key-value +// pair to the environment. +// +// If `src` cannot be decoded as a json dictionary, an error is returned. +func (env *Env) Decode(src io.Reader) error { + m := make(map[string]interface{}) + if err := json.NewDecoder(src).Decode(&m); err != nil { + return err + } + for k, v := range m { + env.SetAuto(k, v) + } + return nil +} + +func (env *Env) SetAuto(k string, v interface{}) { + if fval, ok := v.(float64); ok { + env.SetInt64(k, int64(fval)) + } else if sval, ok := v.(string); ok { + env.Set(k, sval) + } else if val, err := json.Marshal(v); err == nil { + env.Set(k, string(val)) + } else { + env.Set(k, fmt.Sprintf("%v", v)) + } +} + +func (env *Env) Map() map[string]string { + if len(*env) == 0 { + return nil + } + m := make(map[string]string) + for _, kv := range *env { + parts := strings.SplitN(kv, "=", 2) + m[parts[0]] = parts[1] + } + return m +} diff --git a/third_party/src/github.com/fsouza/go-dockerclient/env_test.go b/third_party/src/github.com/fsouza/go-dockerclient/env_test.go new file mode 100644 index 0000000000000..e7a821f81ea52 --- /dev/null +++ b/third_party/src/github.com/fsouza/go-dockerclient/env_test.go @@ -0,0 +1,349 @@ +// Copyright 2014 go-dockerclient authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the DOCKER-LICENSE file. + +package docker + +import ( + "bytes" + "errors" + "reflect" + "sort" + "testing" +) + +func TestGet(t *testing.T) { + var tests = []struct { + input []string + query string + expected string + }{ + {[]string{"PATH=/usr/bin:/bin", "PYTHONPATH=/usr/local"}, "PATH", "/usr/bin:/bin"}, + {[]string{"PATH=/usr/bin:/bin", "PYTHONPATH=/usr/local"}, "PYTHONPATH", "/usr/local"}, + {[]string{"PATH=/usr/bin:/bin", "PYTHONPATH=/usr/local"}, "PYTHONPATHI", ""}, + {[]string{"WAT="}, "WAT", ""}, + } + for _, tt := range tests { + env := Env(tt.input) + got := env.Get(tt.query) + if got != tt.expected { + t.Errorf("Env.Get(%q): wrong result. Want %q. Got %q", tt.query, tt.expected, got) + } + } +} + +func TestExists(t *testing.T) { + var tests = []struct { + input []string + query string + expected bool + }{ + {[]string{"WAT=", "PYTHONPATH=/usr/local"}, "WAT", true}, + {[]string{"PATH=/usr/bin:/bin", "PYTHONPATH=/usr/local"}, "PYTHONPATH", true}, + {[]string{"PATH=/usr/bin:/bin", "PYTHONPATH=/usr/local"}, "PYTHONPATHI", false}, + } + for _, tt := range tests { + env := Env(tt.input) + got := env.Exists(tt.query) + if got != tt.expected { + t.Errorf("Env.Exists(%q): wrong result. Want %v. Got %v", tt.query, tt.expected, got) + } + } +} + +func TestGetBool(t *testing.T) { + var tests = []struct { + input string + expected bool + }{ + {"EMTPY_VAR", false}, {"ZERO_VAR", false}, {"NO_VAR", false}, + {"FALSE_VAR", false}, {"NONE_VAR", false}, {"TRUE_VAR", true}, + {"WAT", true}, {"PATH", true}, {"ONE_VAR", true}, {"NO_VAR_TAB", false}, + } + env := Env([]string{ + "EMPTY_VAR=", "ZERO_VAR=0", "NO_VAR=no", "FALSE_VAR=false", + "NONE_VAR=none", "TRUE_VAR=true", "WAT=wat", "PATH=/usr/bin:/bin", + "ONE_VAR=1", "NO_VAR_TAB=0 \t\t\t", + }) + for _, tt := range tests { + got := env.GetBool(tt.input) + if got != tt.expected { + t.Errorf("Env.GetBool(%q): wrong result. Want %v. Got %v.", tt.input, tt.expected, got) + } + } +} + +func TestSetBool(t *testing.T) { + var tests = []struct { + input bool + expected string + }{ + {true, "1"}, {false, "0"}, + } + for _, tt := range tests { + var env Env + env.SetBool("SOME", tt.input) + if got := env.Get("SOME"); got != tt.expected { + t.Errorf("Env.SetBool(%v): wrong result. Want %q. Got %q", tt.input, tt.expected, got) + } + } +} + +func TestGetInt(t *testing.T) { + var tests = []struct { + input string + expected int + }{ + {"NEGATIVE_INTEGER", -10}, {"NON_INTEGER", -1}, {"ONE", 1}, {"TWO", 2}, + } + env := Env([]string{"NEGATIVE_INTEGER=-10", "NON_INTEGER=wat", "ONE=1", "TWO=2"}) + for _, tt := range tests { + got := env.GetInt(tt.input) + if got != tt.expected { + t.Errorf("Env.GetInt(%q): wrong result. Want %d. Got %d", tt.input, tt.expected, got) + } + } +} + +func TestSetInt(t *testing.T) { + var tests = []struct { + input int + expected string + }{ + {10, "10"}, {13, "13"}, {7, "7"}, {33, "33"}, + {0, "0"}, {-34, "-34"}, + } + for _, tt := range tests { + var env Env + env.SetInt("SOME", tt.input) + if got := env.Get("SOME"); got != tt.expected { + t.Errorf("Env.SetBool(%d): wrong result. Want %q. Got %q", tt.input, tt.expected, got) + } + } +} + +func TestGetInt64(t *testing.T) { + var tests = []struct { + input string + expected int64 + }{ + {"NEGATIVE_INTEGER", -10}, {"NON_INTEGER", -1}, {"ONE", 1}, {"TWO", 2}, + } + env := Env([]string{"NEGATIVE_INTEGER=-10", "NON_INTEGER=wat", "ONE=1", "TWO=2"}) + for _, tt := range tests { + got := env.GetInt64(tt.input) + if got != tt.expected { + t.Errorf("Env.GetInt64(%q): wrong result. Want %d. Got %d", tt.input, tt.expected, got) + } + } +} + +func TestSetInt64(t *testing.T) { + var tests = []struct { + input int64 + expected string + }{ + {10, "10"}, {13, "13"}, {7, "7"}, {33, "33"}, + {0, "0"}, {-34, "-34"}, + } + for _, tt := range tests { + var env Env + env.SetInt64("SOME", tt.input) + if got := env.Get("SOME"); got != tt.expected { + t.Errorf("Env.SetBool(%d): wrong result. Want %q. Got %q", tt.input, tt.expected, got) + } + } +} + +func TestGetJson(t *testing.T) { + var p struct { + Name string `json:"name"` + Age int `json:"age"` + } + var env Env + env.Set("person", `{"name":"Gopher","age":5}`) + err := env.GetJson("person", &p) + if err != nil { + t.Error(err) + } + if p.Name != "Gopher" { + t.Errorf("Env.GetJson(%q): wrong name. Want %q. Got %q", "person", "Gopher", p.Name) + } + if p.Age != 5 { + t.Errorf("Env.GetJson(%q): wrong age. Want %d. Got %d", "person", 5, p.Age) + } +} + +func TestGetJsonAbsent(t *testing.T) { + var l []string + var env Env + err := env.GetJson("person", &l) + if err != nil { + t.Error(err) + } + if l != nil { + t.Errorf("Env.GetJson(): get unexpected list %v", l) + } +} + +func TestGetJsonFailure(t *testing.T) { + var p []string + var env Env + env.Set("list-person", `{"name":"Gopher","age":5}`) + err := env.GetJson("list-person", &p) + if err == nil { + t.Errorf("Env.GetJson(%q): got unexpected error.", "list-person") + } +} + +func TestSetJson(t *testing.T) { + var p1 = struct { + Name string `json:"name"` + Age int `json:"age"` + }{Name: "Gopher", Age: 5} + var env Env + err := env.SetJson("person", p1) + if err != nil { + t.Error(err) + } + var p2 struct { + Name string `json:"name"` + Age int `json:"age"` + } + err = env.GetJson("person", &p2) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(p1, p2) { + t.Errorf("Env.SetJson(%q): wrong result. Want %v. Got %v", "person", p1, p2) + } +} + +func TestSetJsonFailure(t *testing.T) { + var env Env + err := env.SetJson("person", unmarshable{}) + if err == nil { + t.Error("Env.SetJson(): got unexpected error") + } + if env.Exists("person") { + t.Errorf("Env.SetJson(): should not define the key %q, but did", "person") + } +} + +func TestGetList(t *testing.T) { + var tests = []struct { + input string + expected []string + }{ + {"WAT=wat", []string{"wat"}}, + {`WAT=["wat","wet","wit","wot","wut"]`, []string{"wat", "wet", "wit", "wot", "wut"}}, + {"WAT=", nil}, + } + for _, tt := range tests { + env := Env([]string{tt.input}) + got := env.GetList("WAT") + if !reflect.DeepEqual(got, tt.expected) { + t.Errorf("Env.GetList(%q): wrong result. Want %v. Got %v", "WAT", tt.expected, got) + } + } +} + +func TestSetList(t *testing.T) { + list := []string{"a", "b", "c"} + var env Env + env.SetList("SOME", list) + if got := env.GetList("SOME"); !reflect.DeepEqual(got, list) { + t.Errorf("Env.SetList(%v): wrong result. Got %v", list, got) + } +} + +func TestSet(t *testing.T) { + var env Env + env.Set("PATH", "/home/bin:/bin") + env.Set("SOMETHING", "/usr/bin") + env.Set("PATH", "/bin") + if expected, got := "/usr/bin", env.Get("SOMETHING"); got != expected { + t.Errorf("Env.Set(%q): wrong result. Want %q. Got %q", expected, expected, got) + } + if expected, got := "/bin", env.Get("PATH"); got != expected { + t.Errorf("Env.Set(%q): wrong result. Want %q. Got %q", expected, expected, got) + } +} + +func TestDecode(t *testing.T) { + var tests = []struct { + input string + expectedOut []string + expectedErr string + }{ + { + `{"PATH":"/usr/bin:/bin","containers":54,"wat":["123","345"]}`, + []string{"PATH=/usr/bin:/bin", "containers=54", `wat=["123","345"]`}, + "", + }, + {"}}", nil, "invalid character '}' looking for beginning of value"}, + {`{}`, nil, ""}, + } + for _, tt := range tests { + var env Env + err := env.Decode(bytes.NewBufferString(tt.input)) + if tt.expectedErr == "" { + if err != nil { + t.Error(err) + } + } else if tt.expectedErr != err.Error() { + t.Errorf("Env.Decode(): invalid error. Want %q. Got %q.", tt.expectedErr, err) + } + got := []string(env) + sort.Strings(got) + sort.Strings(tt.expectedOut) + if !reflect.DeepEqual(got, tt.expectedOut) { + t.Errorf("Env.Decode(): wrong result. Want %v. Got %v.", tt.expectedOut, got) + } + } +} + +func TestSetAuto(t *testing.T) { + buf := bytes.NewBufferString("oi") + var tests = []struct { + input interface{} + expected string + }{ + {10, "10"}, + {10.3, "10"}, + {"oi", "oi"}, + {buf, "{}"}, + {unmarshable{}, "{}"}, + } + for _, tt := range tests { + var env Env + env.SetAuto("SOME", tt.input) + if got := env.Get("SOME"); got != tt.expected { + t.Errorf("Env.SetAuto(%v): wrong result. Want %q. Got %q", tt.input, tt.expected, got) + } + } +} + +func TestMap(t *testing.T) { + var tests = []struct { + input []string + expected map[string]string + }{ + {[]string{"PATH=/usr/bin:/bin", "PYTHONPATH=/usr/local"}, map[string]string{"PATH": "/usr/bin:/bin", "PYTHONPATH": "/usr/local"}}, + {nil, nil}, + } + for _, tt := range tests { + env := Env(tt.input) + got := env.Map() + if !reflect.DeepEqual(got, tt.expected) { + t.Errorf("Env.Map(): wrong result. Want %v. Got %v", tt.expected, got) + } + } +} + +type unmarshable struct { +} + +func (unmarshable) MarshalJSON() ([]byte, error) { + return nil, errors.New("cannot marshal") +} diff --git a/third_party/src/github.com/fsouza/go-dockerclient/event_test.go b/third_party/src/github.com/fsouza/go-dockerclient/event_test.go index bf498d3cf0e06..cb54f4ae925a8 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/event_test.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/event_test.go @@ -53,7 +53,7 @@ func TestEventListeners(t *testing.T) { for { select { case msg := <-listener: - t.Logf("Received: %s", *msg) + t.Logf("Recieved: %s", *msg) count++ err = checkEvent(count, msg) if err != nil { diff --git a/third_party/src/github.com/fsouza/go-dockerclient/image_test.go b/third_party/src/github.com/fsouza/go-dockerclient/image_test.go index a2db84db15565..12928b37c511f 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/image_test.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/image_test.go @@ -21,9 +21,9 @@ func newTestClient(rt *FakeRoundTripper) Client { endpoint := "http://localhost:4243" u, _ := parseEndpoint("http://localhost:4243") client := Client{ + HTTPClient: &http.Client{Transport: rt}, endpoint: endpoint, endpointURL: u, - client: &http.Client{Transport: rt}, SkipServerVersionCheck: true, } return client diff --git a/third_party/src/github.com/fsouza/go-dockerclient/misc.go b/third_party/src/github.com/fsouza/go-dockerclient/misc.go index 1b9267e28a337..3d0e9c803df4d 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/misc.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/misc.go @@ -6,39 +6,32 @@ package docker import ( "bytes" - "io" - - "github.com/fsouza/go-dockerclient/engine" ) // Version returns version information about the docker server. // // See http://goo.gl/IqKNRE for more details. -func (c *Client) Version() (*engine.Env, error) { +func (c *Client) Version() (*Env, error) { body, _, err := c.do("GET", "/version", nil) if err != nil { return nil, err } - out := engine.NewOutput() - remoteVersion, err := out.AddEnv() - if err != nil { - return nil, err - } - if _, err := io.Copy(out, bytes.NewReader(body)); err != nil { + var env Env + if err := env.Decode(bytes.NewReader(body)); err != nil { return nil, err } - return remoteVersion, nil + return &env, nil } // Info returns system-wide information, like the number of running containers. // // See http://goo.gl/LOmySw for more details. -func (c *Client) Info() (*engine.Env, error) { +func (c *Client) Info() (*Env, error) { body, _, err := c.do("GET", "/info", nil) if err != nil { return nil, err } - var info engine.Env + var info Env err = info.Decode(bytes.NewReader(body)) if err != nil { return nil, err diff --git a/third_party/src/github.com/fsouza/go-dockerclient/misc_test.go b/third_party/src/github.com/fsouza/go-dockerclient/misc_test.go index 8cf283e565f2b..d8e9b58dc43a9 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/misc_test.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/misc_test.go @@ -10,8 +10,6 @@ import ( "reflect" "sort" "testing" - - "github.com/fsouza/go-dockerclient/engine" ) type DockerVersion struct { @@ -81,7 +79,7 @@ func TestInfo(t *testing.T) { }` fakeRT := FakeRoundTripper{message: body, status: http.StatusOK} client := newTestClient(&fakeRT) - expected := engine.Env{} + expected := Env{} expected.SetInt("Containers", 11) expected.SetInt("Images", 16) expected.SetBool("Debug", false) diff --git a/third_party/src/github.com/fsouza/go-dockerclient/testing/server.go b/third_party/src/github.com/fsouza/go-dockerclient/testing/server.go index d79fcd492341d..03e6ca4c74325 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/testing/server.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/testing/server.go @@ -170,6 +170,12 @@ func (s *DockerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } +// Returns default http.Handler mux, it allows customHandlers to call the +// default behavior if wanted. +func (s *DockerServer) DefaultHandler() http.Handler { + return s.mux +} + func (s *DockerServer) handlerWrapper(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { for errorID, urlRegexp := range s.failures { @@ -218,6 +224,11 @@ func (s *DockerServer) listImages(w http.ResponseWriter, r *http.Request) { ID: image.ID, Created: image.Created.Unix(), } + for tag, id := range s.imgIDs { + if id == image.ID { + result[i].RepoTags = append(result[i].RepoTags, tag) + } + } } s.cMut.RUnlock() w.Header().Set("Content-Type", "application/json") @@ -563,8 +574,9 @@ func (s *DockerServer) pushImage(w http.ResponseWriter, r *http.Request) { func (s *DockerServer) removeImage(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] s.iMut.RLock() + var tag string if img, ok := s.imgIDs[id]; ok { - id = img + id, tag = img, id } s.iMut.RUnlock() _, index, err := s.findImageByID(id) @@ -577,6 +589,9 @@ func (s *DockerServer) removeImage(w http.ResponseWriter, r *http.Request) { defer s.iMut.Unlock() s.images[index] = s.images[len(s.images)-1] s.images = s.images[:len(s.images)-1] + if tag != "" { + delete(s.imgIDs, tag) + } } func (s *DockerServer) inspectImage(w http.ResponseWriter, r *http.Request) { diff --git a/third_party/src/github.com/fsouza/go-dockerclient/testing/server_test.go b/third_party/src/github.com/fsouza/go-dockerclient/testing/server_test.go index bbd4654fd6c75..97c3687ec6762 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/testing/server_test.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/testing/server_test.go @@ -780,7 +780,7 @@ func addImages(server *DockerServer, n int, repo bool) { func TestListImages(t *testing.T) { server := DockerServer{} - addImages(&server, 2, false) + addImages(&server, 2, true) server.buildMuxer() recorder := httptest.NewRecorder() request, _ := http.NewRequest("GET", "/images/json?all=1", nil) @@ -791,8 +791,9 @@ func TestListImages(t *testing.T) { expected := make([]docker.APIImages, 2) for i, image := range server.images { expected[i] = docker.APIImages{ - ID: image.ID, - Created: image.Created.Unix(), + ID: image.ID, + Created: image.Created.Unix(), + RepoTags: []string{"docker/python-" + image.ID}, } } var got []docker.APIImages @@ -826,7 +827,8 @@ func TestRemoveImageByName(t *testing.T) { addImages(&server, 1, true) server.buildMuxer() recorder := httptest.NewRecorder() - path := "/images/docker/python-" + server.images[0].ID + imgName := "docker/python-" + server.images[0].ID + path := "/images/" + imgName request, _ := http.NewRequest("DELETE", path, nil) server.ServeHTTP(recorder, request) if recorder.Code != http.StatusNoContent { @@ -835,6 +837,10 @@ func TestRemoveImageByName(t *testing.T) { if len(server.images) > 0 { t.Error("RemoveImage: did not remove the image.") } + _, ok := server.imgIDs[imgName] + if ok { + t.Error("RemoveImage: did not remove image tag name.") + } } func TestPrepareFailure(t *testing.T) { @@ -945,3 +951,14 @@ func TestPing(t *testing.T) { t.Errorf("Ping: Expected code %d, got: %d", http.StatusOK, recorder.Code) } } + +func TestDefaultHandler(t *testing.T) { + server, err := NewServer("127.0.0.1:0", nil, nil) + if err != nil { + t.Fatal(err) + } + defer server.listener.Close() + if server.mux != server.DefaultHandler() { + t.Fatalf("DefaultHandler: Expected to return server.mux, got: %#v", server.DefaultHandler()) + } +} diff --git a/third_party/src/github.com/fsouza/go-dockerclient/utils/stdcopy.go b/third_party/src/github.com/fsouza/go-dockerclient/utils/stdcopy.go index dec604ce48947..ca502ecf5736a 100644 --- a/third_party/src/github.com/fsouza/go-dockerclient/utils/stdcopy.go +++ b/third_party/src/github.com/fsouza/go-dockerclient/utils/stdcopy.go @@ -109,7 +109,6 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) // Write on stderr out = dsterr default: - Debugf("Error selecting output fd: (%d)", buf[StdWriterFdIndex]) return 0, ErrInvalidStdHeader } @@ -119,7 +118,6 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) // Check if the buffer is big enough to read the frame. // Extend it if necessary. if frameSize+StdWriterPrefixLen > bufLen { - Debugf("Extending buffer cap.") buf = append(buf, make([]byte, frameSize+StdWriterPrefixLen-len(buf)+1)...) bufLen = len(buf) } @@ -135,7 +133,6 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) nr += nr2 break } else if er != nil { - Debugf("Error reading frame: %s", er) return 0, er } nr += nr2 @@ -151,12 +148,10 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) written += int64(nw) } if ew != nil { - Debugf("Error writing frame: %s", ew) return 0, ew } // If the frame has not been fully written: error if nw != frameSize { - Debugf("Error Short Write: (%d on %d)", nw, frameSize) return written, io.ErrShortWrite }