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).
pull/6/head
Francisco Souza 2014-07-30 15:18:42 -03:00
parent dc6fdc423d
commit 2a345ffa9e
16 changed files with 656 additions and 101 deletions

View File

@ -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,

View File

@ -1,5 +1,6 @@
# This is the official list of go-dockerclient authors for copyright purposes.
Andreas Jaekle <andreas@jaekle.net>
Andrews Medina <andrewsmedina@gmail.com>
Andy Goldstein <andy.goldstein@redhat.com>
Ben McCann <benmccann.com>
@ -8,6 +9,7 @@ Cheah Chu Yeow <chuyeow@gmail.com>
cheneydeng <cheneydeng@qq.com>
Ed <edrocksit@gmail.com>
Eric Anderson <anderson@copperegg.com>
Fabio Rehm <fgrehm@gmail.com>
Flavia Missi <flaviamissi@gmail.com>
Francisco Souza <f@souza.cc>
Jari Kolehmainen <jari.kolehmainen@digia.com>
@ -15,6 +17,8 @@ Jason Wilder <jwilder@litl.com>
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
Jeff Mitchell <jeffrey.mitchell@gmail.com>
Jeffrey Hulten <jhulten@gmail.com>
Johan Euphrosine <proppy@google.com>
Karan Misra <kidoman@gmail.com>
Lucas Clemente <lucas@clemente.io>
Omeid Matten <public@omeid.me>
Paul Morie <pmorie@gmail.com>

View File

@ -11,27 +11,29 @@ For more details, check the [remote API documentation](http://docs.docker.io/en/
## Example
package main
```go
package main
import (
"fmt"
"github.com/fsouza/go-dockerclient"
)
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)
}
}
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

View File

@ -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 {

View File

@ -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)

View File

@ -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 {

View File

@ -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)

View File

@ -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
}

View File

@ -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 <nil> 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 <nil> 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")
}

View File

@ -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 {

View File

@ -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

View File

@ -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 {
var env Env
if err := env.Decode(bytes.NewReader(body)); err != nil {
return nil, err
}
if _, err := io.Copy(out, 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

View File

@ -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)

View File

@ -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) {

View File

@ -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())
}
}

View File

@ -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
}