Commit 7464575b authored by Dawn Chen's avatar Dawn Chen

Merge pull request #6698 from pweil-/update-dockercli

Update to latest docker client
parents 86d30724 fb633704
...@@ -174,7 +174,7 @@ ...@@ -174,7 +174,7 @@
}, },
{ {
"ImportPath": "github.com/fsouza/go-dockerclient", "ImportPath": "github.com/fsouza/go-dockerclient",
"Rev": "d19717788084716e4adff0515be6289aa04bec46" "Rev": "17d39bcb22e8103ba6d1c0cb2530c6434cb870a3"
}, },
{ {
"ImportPath": "github.com/garyburd/redigo/internal", "ImportPath": "github.com/garyburd/redigo/internal",
......
language: go language: go
go: go:
- 1.2.2
- 1.3.1 - 1.3.1
- 1.4 - 1.4
- tip - tip
......
# This is the official list of go-dockerclient authors for copyright purposes. # This is the official list of go-dockerclient authors for copyright purposes.
Adam Bell-Hanssen <adamb@aller.no>
Aldrin Leal <aldrin@leal.eng.br> Aldrin Leal <aldrin@leal.eng.br>
Andreas Jaekle <andreas@jaekle.net> Andreas Jaekle <andreas@jaekle.net>
Andrews Medina <andrewsmedina@gmail.com> Andrews Medina <andrewsmedina@gmail.com>
Artem Sidorenko <artem@2realities.com> Artem Sidorenko <artem@2realities.com>
Andy Goldstein <andy.goldstein@redhat.com> Andy Goldstein <andy.goldstein@redhat.com>
Ben Marini <ben@remind101.com>
Ben McCann <benmccann.com> Ben McCann <benmccann.com>
Brian Lalor <blalor@bravo5.org>
Burke Libbey <burke@libbey.me>
Carlos Diaz-Padron <cpadron@mozilla.com> Carlos Diaz-Padron <cpadron@mozilla.com>
Cezar Sa Espinola <cezar.sa@corp.globo.com> Cezar Sa Espinola <cezar.sa@corp.globo.com>
Cheah Chu Yeow <chuyeow@gmail.com> Cheah Chu Yeow <chuyeow@gmail.com>
cheneydeng <cheneydeng@qq.com> cheneydeng <cheneydeng@qq.com>
CMGS <ilskdw@gmail.com> CMGS <ilskdw@gmail.com>
Daniel, Dao Quang Minh <dqminh89@gmail.com> Daniel, Dao Quang Minh <dqminh89@gmail.com>
Darren Shepherd <darren@rancher.com>
David Huie <dahuie@gmail.com> David Huie <dahuie@gmail.com>
Dawn Chen <dawnchen@google.com> Dawn Chen <dawnchen@google.com>
Ed <edrocksit@gmail.com> Ed <edrocksit@gmail.com>
Eric Anderson <anderson@copperegg.com> Eric Anderson <anderson@copperegg.com>
Fabio Rehm <fgrehm@gmail.com> Fabio Rehm <fgrehm@gmail.com>
Fatih Arslan <ftharsln@gmail.com> Fatih Arslan <ftharsln@gmail.com>
Flavia Missi <flaviamissi@gmail.com> Flavia Missi <flaviamissi@gmail.com>
Francisco Souza <f@souza.cc> Francisco Souza <f@souza.cc>
Guillermo Álvarez Fernández <guillermo@cientifico.net>
Jari Kolehmainen <jari.kolehmainen@digia.com> Jari Kolehmainen <jari.kolehmainen@digia.com>
Jason Wilder <jwilder@litl.com> Jason Wilder <jwilder@litl.com>
Jawher Moussa <jawher.moussa@gmail.com> Jawher Moussa <jawher.moussa@gmail.com>
...@@ -30,19 +36,26 @@ Johan Euphrosine <proppy@google.com> ...@@ -30,19 +36,26 @@ Johan Euphrosine <proppy@google.com>
Kamil Domanski <kamil@domanski.co> Kamil Domanski <kamil@domanski.co>
Karan Misra <kidoman@gmail.com> Karan Misra <kidoman@gmail.com>
Kim, Hirokuni <hirokuni.kim@kvh.co.jp> Kim, Hirokuni <hirokuni.kim@kvh.co.jp>
liron-l <levinlir@gmail.com>
Lucas Clemente <lucas@clemente.io> Lucas Clemente <lucas@clemente.io>
Lucas Weiblen <lucasweiblen@gmail.com>
Mantas Matelis <mmatelis@coursera.org>
Martin Sweeney <martin@sweeney.io> Martin Sweeney <martin@sweeney.io>
Máximo Cuadros Ortiz <mcuadros@gmail.com> Máximo Cuadros Ortiz <mcuadros@gmail.com>
Michal Fojtik <mfojtik@redhat.com>
Mike Dillon <mike.dillon@synctree.com> Mike Dillon <mike.dillon@synctree.com>
Mrunal Patel <mrunalp@gmail.com> Mrunal Patel <mrunalp@gmail.com>
Nick Ethier <ncethier@gmail.com>
Omeid Matten <public@omeid.me> Omeid Matten <public@omeid.me>
Paul Morie <pmorie@gmail.com> Paul Morie <pmorie@gmail.com>
Paul Weil <pweil@redhat.com>
Peter Jihoon Kim <raingrove@gmail.com> Peter Jihoon Kim <raingrove@gmail.com>
Philippe Lafoucrière <philippe.lafoucriere@tech-angels.com> Philippe Lafoucrière <philippe.lafoucriere@tech-angels.com>
Rafe Colton <rafael.colton@gmail.com> Rafe Colton <rafael.colton@gmail.com>
Rob Miller <rob@kalistra.com> Rob Miller <rob@kalistra.com>
Robert Williamson <williamson.robert@gmail.com> Robert Williamson <williamson.robert@gmail.com>
Salvador Gironès <salvadorgirones@gmail.com> Salvador Gironès <salvadorgirones@gmail.com>
Sam Rijs <srijs@airpost.net>
Simon Eskildsen <sirup@sirupsen.com> Simon Eskildsen <sirup@sirupsen.com>
Simon Menke <simon.menke@gmail.com> Simon Menke <simon.menke@gmail.com>
Skolos <skolos@gopherlab.com> Skolos <skolos@gopherlab.com>
...@@ -51,5 +64,7 @@ Sridhar Ratnakumar <sridharr@activestate.com> ...@@ -51,5 +64,7 @@ Sridhar Ratnakumar <sridharr@activestate.com>
Summer Mousa <smousa@zenoss.com> Summer Mousa <smousa@zenoss.com>
Tarsis Azevedo <tarsis@corp.globo.com> Tarsis Azevedo <tarsis@corp.globo.com>
Tim Schindler <tim@catalyst-zero.com> Tim Schindler <tim@catalyst-zero.com>
Vincenzo Prignano <vincenzo.prignano@gmail.com>
Wiliam Souza <wiliamsouza83@gmail.com> Wiliam Souza <wiliamsouza83@gmail.com>
Ye Yin <eyniy@qq.com> Ye Yin <eyniy@qq.com>
Yuriy Bogdanov <chinsay@gmail.com>
Copyright (c) 2014, go-dockerclient authors Copyright (c) 2015, go-dockerclient authors
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
......
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
[![Build Status](https://drone.io/github.com/fsouza/go-dockerclient/status.png)](https://drone.io/github.com/fsouza/go-dockerclient/latest) [![Build Status](https://drone.io/github.com/fsouza/go-dockerclient/status.png)](https://drone.io/github.com/fsouza/go-dockerclient/latest)
[![Build Status](https://travis-ci.org/fsouza/go-dockerclient.png)](https://travis-ci.org/fsouza/go-dockerclient) [![Build Status](https://travis-ci.org/fsouza/go-dockerclient.png)](https://travis-ci.org/fsouza/go-dockerclient)
[![GoDoc](http://godoc.org/github.com/fsouza/go-dockerclient?status.png)](http://godoc.org/github.com/fsouza/go-dockerclient) [![GoDoc](https://godoc.org/github.com/fsouza/go-dockerclient?status.png)](https://godoc.org/github.com/fsouza/go-dockerclient)
This package presents a client for the Docker remote API. This package presents a client for the Docker remote API. It also provides
support for the extensions in the [Swarm API](https://docs.docker.com/swarm/API/).
For more details, check the [remote API documentation](http://docs.docker.io/en/latest/reference/api/docker_remote_api/). For more details, check the [remote API documentation](http://docs.docker.com/en/latest/reference/api/docker_remote_api/).
## Example ## Example
...@@ -15,22 +16,49 @@ For more details, check the [remote API documentation](http://docs.docker.io/en/ ...@@ -15,22 +16,49 @@ For more details, check the [remote API documentation](http://docs.docker.io/en/
package main package main
import ( import (
"fmt" "fmt"
"github.com/fsouza/go-dockerclient"
"github.com/fsouza/go-dockerclient"
)
func main() {
endpoint := "unix:///var/run/docker.sock"
client, _ := docker.NewClient(endpoint)
imgs, _ := client.ListImages(docker.ListImagesOptions{All: false})
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)
}
}
```
## Using with Boot2Docker
Boot2Docker runs Docker with TLS enabled. In order to instantiate the client you should use NewTLSClient, passing the endpoint and path for key and certificates as parameters.
For more details about TLS support in Boot2Docker, please refer to [TLS support](https://github.com/boot2docker/boot2docker#tls-support) on Boot2Docker's readme.
```go
package main
import (
"fmt"
"github.com/fsouza/go-dockerclient"
) )
func main() { func main() {
endpoint := "unix:///var/run/docker.sock" endpoint := "tcp://[ip]:[port]"
client, _ := docker.NewClient(endpoint) path := os.Getenv("DOCKER_CERT_PATH")
imgs, _ := client.ListImages(docker.ListImagesOptions{All: false}) ca := fmt.Sprintf("%s/ca.pem", path)
for _, img := range imgs { cert := fmt.Sprintf("%s/cert.pem", path)
fmt.Println("ID: ", img.ID) key := fmt.Sprintf("%s/key.pem", path)
fmt.Println("RepoTags: ", img.RepoTags) client, _ := docker.NewTLSClient(endpoint, cert, key, ca)
fmt.Println("Created: ", img.Created) // use client
fmt.Println("Size: ", img.Size)
fmt.Println("VirtualSize: ", img.VirtualSize)
fmt.Println("ParentId: ", img.ParentID)
}
} }
``` ```
......
// Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package docker
import (
"encoding/base64"
"encoding/json"
"io"
"os"
"path"
"strings"
)
// AuthConfiguration represents authentication options to use in the PushImage
// method. It represents the authentication in the Docker index server.
type AuthConfiguration struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Email string `json:"email,omitempty"`
ServerAddress string `json:"serveraddress,omitempty"`
}
// AuthConfigurations represents authentication options to use for the
// PushImage method accommodating the new X-Registry-Config header
type AuthConfigurations struct {
Configs map[string]AuthConfiguration `json:"configs"`
}
// dockerConfig represents a registry authentation configuration from the
// .dockercfg file.
type dockerConfig struct {
Auth string `json:"auth"`
Email string `json:"email"`
}
// NewAuthConfigurationsFromDockerCfg returns AuthConfigurations from the
// ~/.dockercfg file.
func NewAuthConfigurationsFromDockerCfg() (*AuthConfigurations, error) {
p := path.Join(os.Getenv("HOME"), ".dockercfg")
r, err := os.Open(p)
if err != nil {
return nil, err
}
return NewAuthConfigurations(r)
}
// NewAuthConfigurations returns AuthConfigurations from a JSON encoded string in the
// same format as the .dockercfg file.
func NewAuthConfigurations(r io.Reader) (*AuthConfigurations, error) {
var auth *AuthConfigurations
var confs map[string]dockerConfig
if err := json.NewDecoder(r).Decode(&confs); err != nil {
return nil, err
}
auth, err := authConfigs(confs)
if err != nil {
return nil, err
}
return auth, nil
}
// authConfigs converts a dockerConfigs map to a AuthConfigurations object.
func authConfigs(confs map[string]dockerConfig) (*AuthConfigurations, error) {
c := &AuthConfigurations{
Configs: make(map[string]AuthConfiguration),
}
for reg, conf := range confs {
data, err := base64.StdEncoding.DecodeString(conf.Auth)
if err != nil {
return nil, err
}
userpass := strings.Split(string(data), ":")
c.Configs[reg] = AuthConfiguration{
Email: conf.Email,
Username: userpass[0],
Password: userpass[1],
ServerAddress: reg,
}
}
return c, nil
}
// Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package docker
import (
"encoding/base64"
"fmt"
"strings"
"testing"
)
func TestAuthConfig(t *testing.T) {
auth := base64.StdEncoding.EncodeToString([]byte("user:pass"))
read := strings.NewReader(fmt.Sprintf(`{"docker.io":{"auth":"%s","email":"user@example.com"}}`, auth))
ac, err := NewAuthConfigurations(read)
if err != nil {
t.Error(err)
}
c, ok := ac.Configs["docker.io"]
if !ok {
t.Error("NewAuthConfigurations: Expected Configs to contain docker.io")
}
if got, want := c.Email, "user@example.com"; got != want {
t.Errorf(`AuthConfigurations.Configs["docker.io"].Email: wrong result. Want %q. Got %q`, want, got)
}
if got, want := c.Username, "user"; got != want {
t.Errorf(`AuthConfigurations.Configs["docker.io"].Username: wrong result. Want %q. Got %q`, want, got)
}
if got, want := c.Password, "pass"; got != want {
t.Errorf(`AuthConfigurations.Configs["docker.io"].Password: wrong result. Want %q. Got %q`, want, got)
}
if got, want := c.ServerAddress, "docker.io"; got != want {
t.Errorf(`AuthConfigurations.Configs["docker.io"].ServerAddress: wrong result. Want %q. Got %q`, want, got)
}
}
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -34,7 +34,7 @@ var ( ...@@ -34,7 +34,7 @@ var (
// ErrConnectionRefused is returned when the client cannot connect to the given endpoint. // ErrConnectionRefused is returned when the client cannot connect to the given endpoint.
ErrConnectionRefused = errors.New("cannot connect to Docker endpoint") ErrConnectionRefused = errors.New("cannot connect to Docker endpoint")
apiVersion1_12, _ = NewAPIVersion("1.12") apiVersion112, _ = NewAPIVersion("1.12")
) )
// APIVersion is an internal representation of a version of the Remote API. // APIVersion is an internal representation of a version of the Remote API.
...@@ -143,7 +143,7 @@ func NewClient(endpoint string) (*Client, error) { ...@@ -143,7 +143,7 @@ func NewClient(endpoint string) (*Client, error) {
// server endpoint, key and certificates . It will use the latest remote API version // server endpoint, key and certificates . It will use the latest remote API version
// available in the server. // available in the server.
func NewTLSClient(endpoint string, cert, key, ca string) (*Client, error) { func NewTLSClient(endpoint string, cert, key, ca string) (*Client, error) {
client, err := NewVersionnedTLSClient(endpoint, cert, key, ca, "") client, err := NewVersionedTLSClient(endpoint, cert, key, ca, "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -154,7 +154,7 @@ func NewTLSClient(endpoint string, cert, key, ca string) (*Client, error) { ...@@ -154,7 +154,7 @@ func NewTLSClient(endpoint string, cert, key, ca string) (*Client, error) {
// NewVersionedClient returns a Client instance ready for communication with // NewVersionedClient returns a Client instance ready for communication with
// the given server endpoint, using a specific remote API version. // the given server endpoint, using a specific remote API version.
func NewVersionedClient(endpoint string, apiVersionString string) (*Client, error) { func NewVersionedClient(endpoint string, apiVersionString string) (*Client, error) {
u, err := parseEndpoint(endpoint) u, err := parseEndpoint(endpoint, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -174,10 +174,15 @@ func NewVersionedClient(endpoint string, apiVersionString string) (*Client, erro ...@@ -174,10 +174,15 @@ func NewVersionedClient(endpoint string, apiVersionString string) (*Client, erro
}, nil }, nil
} }
// NewVersionnedTLSClient returns a Client instance ready for TLS communications with the givens // NewVersionnedTLSClient has been DEPRECATED, please use NewVersionedTLSClient.
// server endpoint, key and certificates, using a specific remote API version.
func NewVersionnedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) { func NewVersionnedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) {
u, err := parseEndpoint(endpoint) return NewVersionedTLSClient(endpoint, cert, key, ca, apiVersionString)
}
// NewVersionedTLSClient returns a Client instance ready for TLS communications with the givens
// server endpoint, key and certificates, using a specific remote API version.
func NewVersionedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) {
u, err := parseEndpoint(endpoint, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -247,7 +252,7 @@ func (c *Client) checkAPIVersion() error { ...@@ -247,7 +252,7 @@ func (c *Client) checkAPIVersion() error {
// See http://goo.gl/stJENm for more details. // See http://goo.gl/stJENm for more details.
func (c *Client) Ping() error { func (c *Client) Ping() error {
path := "/_ping" path := "/_ping"
body, status, err := c.do("GET", path, nil) body, status, err := c.do("GET", path, nil, false)
if err != nil { if err != nil {
return err return err
} }
...@@ -258,7 +263,7 @@ func (c *Client) Ping() error { ...@@ -258,7 +263,7 @@ func (c *Client) Ping() error {
} }
func (c *Client) getServerAPIVersionString() (version string, err error) { func (c *Client) getServerAPIVersionString() (version string, err error) {
body, status, err := c.do("GET", "/version", nil) body, status, err := c.do("GET", "/version", nil, false)
if err != nil { if err != nil {
return "", err return "", err
} }
...@@ -274,9 +279,9 @@ func (c *Client) getServerAPIVersionString() (version string, err error) { ...@@ -274,9 +279,9 @@ func (c *Client) getServerAPIVersionString() (version string, err error) {
return version, nil return version, nil
} }
func (c *Client) do(method, path string, data interface{}) ([]byte, int, error) { func (c *Client) do(method, path string, data interface{}, forceJSON bool) ([]byte, int, error) {
var params io.Reader var params io.Reader
if data != nil { if data != nil || forceJSON {
buf, err := json.Marshal(data) buf, err := json.Marshal(data)
if err != nil { if err != nil {
return nil, -1, err return nil, -1, err
...@@ -599,11 +604,14 @@ func (e *Error) Error() string { ...@@ -599,11 +604,14 @@ func (e *Error) Error() string {
return fmt.Sprintf("API error (%d): %s", e.Status, e.Message) return fmt.Sprintf("API error (%d): %s", e.Status, e.Message)
} }
func parseEndpoint(endpoint string) (*url.URL, error) { func parseEndpoint(endpoint string, tls bool) (*url.URL, error) {
u, err := url.Parse(endpoint) u, err := url.Parse(endpoint)
if err != nil { if err != nil {
return nil, ErrInvalidEndpoint return nil, ErrInvalidEndpoint
} }
if tls {
u.Scheme = "https"
}
if u.Scheme == "tcp" { if u.Scheme == "tcp" {
_, port, err := net.SplitHostPort(u.Host) _, port, err := net.SplitHostPort(u.Host)
if err != nil { if err != nil {
......
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -93,7 +93,7 @@ func TestNewTLSVersionedClient(t *testing.T) { ...@@ -93,7 +93,7 @@ func TestNewTLSVersionedClient(t *testing.T) {
keyPath := "testing/data/key.pem" keyPath := "testing/data/key.pem"
caPath := "testing/data/ca.pem" caPath := "testing/data/ca.pem"
endpoint := "https://localhost:4243" endpoint := "https://localhost:4243"
client, err := NewVersionnedTLSClient(endpoint, certPath, keyPath, caPath, "1.14") client, err := NewVersionedTLSClient(endpoint, certPath, keyPath, caPath, "1.14")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -113,7 +113,7 @@ func TestNewTLSVersionedClientInvalidCA(t *testing.T) { ...@@ -113,7 +113,7 @@ func TestNewTLSVersionedClientInvalidCA(t *testing.T) {
keyPath := "testing/data/key.pem" keyPath := "testing/data/key.pem"
caPath := "testing/data/key.pem" caPath := "testing/data/key.pem"
endpoint := "https://localhost:4243" endpoint := "https://localhost:4243"
_, err := NewVersionnedTLSClient(endpoint, certPath, keyPath, caPath, "1.14") _, err := NewVersionedTLSClient(endpoint, certPath, keyPath, caPath, "1.14")
if err == nil { if err == nil {
t.Errorf("Expected invalid ca at %s", caPath) t.Errorf("Expected invalid ca at %s", caPath)
} }
...@@ -136,14 +136,15 @@ func TestNewClientInvalidEndpoint(t *testing.T) { ...@@ -136,14 +136,15 @@ func TestNewClientInvalidEndpoint(t *testing.T) {
} }
} }
func TestNewTLSClient2376(t *testing.T) { func TestNewTLSClient(t *testing.T) {
var tests = []struct { var tests = []struct {
endpoint string endpoint string
expected string expected string
}{ }{
{"tcp://localhost:2376", "https"}, {"tcp://localhost:2376", "https"},
{"tcp://localhost:2375", "http"}, {"tcp://localhost:2375", "https"},
{"tcp://localhost:4000", "http"}, {"tcp://localhost:4000", "https"},
{"http://localhost:4000", "https"},
} }
for _, tt := range tests { for _, tt := range tests {
......
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -7,6 +7,7 @@ package docker ...@@ -7,6 +7,7 @@ package docker
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"io/ioutil" "io/ioutil"
"net" "net"
"net/http" "net/http"
...@@ -154,6 +155,7 @@ func TestListContainersFailure(t *testing.T) { ...@@ -154,6 +155,7 @@ func TestListContainersFailure(t *testing.T) {
func TestInspectContainer(t *testing.T) { func TestInspectContainer(t *testing.T) {
jsonContainer := `{ jsonContainer := `{
"Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2", "Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
"AppArmorProfile": "Profile",
"Created": "2013-05-07T14:51:42.087658+02:00", "Created": "2013-05-07T14:51:42.087658+02:00",
"Path": "date", "Path": "date",
"Args": [], "Args": [],
...@@ -175,7 +177,10 @@ func TestInspectContainer(t *testing.T) { ...@@ -175,7 +177,10 @@ func TestInspectContainer(t *testing.T) {
], ],
"Image": "base", "Image": "base",
"Volumes": {}, "Volumes": {},
"VolumesFrom": "" "VolumesFrom": "",
"SecurityOpt": [
"label:user:USER"
]
}, },
"State": { "State": {
"Running": false, "Running": false,
...@@ -184,6 +189,21 @@ func TestInspectContainer(t *testing.T) { ...@@ -184,6 +189,21 @@ func TestInspectContainer(t *testing.T) {
"StartedAt": "2013-05-07T14:51:42.087658+02:00", "StartedAt": "2013-05-07T14:51:42.087658+02:00",
"Ghost": false "Ghost": false
}, },
"Node": {
"ID": "4I4E:QR4I:Z733:QEZK:5X44:Q4T7:W2DD:JRDY:KB2O:PODO:Z5SR:XRB6",
"IP": "192.168.99.105",
"Addra": "192.168.99.105:2376",
"Name": "node-01",
"Cpus": 4,
"Memory": 1048436736,
"Labels": {
"executiondriver": "native-0.2",
"kernelversion": "3.18.5-tinycore64",
"operatingsystem": "Boot2Docker 1.5.0 (TCL 5.4); master : a66bce5 - Tue Feb 10 23:31:27 UTC 2015",
"provider": "virtualbox",
"storagedriver": "aufs"
}
},
"Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", "Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
"NetworkSettings": { "NetworkSettings": {
"IpAddress": "", "IpAddress": "",
...@@ -511,12 +531,17 @@ func TestStartContainerNilHostConfig(t *testing.T) { ...@@ -511,12 +531,17 @@ func TestStartContainerNilHostConfig(t *testing.T) {
if contentType := req.Header.Get("Content-Type"); contentType != expectedContentType { if contentType := req.Header.Get("Content-Type"); contentType != expectedContentType {
t.Errorf("StartContainer(%q): Wrong content-type in request. Want %q. Got %q.", id, expectedContentType, contentType) t.Errorf("StartContainer(%q): Wrong content-type in request. Want %q. Got %q.", id, expectedContentType, contentType)
} }
var buf [4]byte
req.Body.Read(buf[:])
if string(buf[:]) != "null" {
t.Errorf("Startcontainer(%q): Wrong body. Want null. Got %s", buf[:])
}
} }
func TestStartContainerNotFound(t *testing.T) { func TestStartContainerNotFound(t *testing.T) {
client := newTestClient(&FakeRoundTripper{message: "no such container", status: http.StatusNotFound}) client := newTestClient(&FakeRoundTripper{message: "no such container", status: http.StatusNotFound})
err := client.StartContainer("a2344", &HostConfig{}) err := client.StartContainer("a2344", &HostConfig{})
expected := &NoSuchContainer{ID: "a2344"} expected := &NoSuchContainer{ID: "a2344", Err: err.(*NoSuchContainer).Err}
if !reflect.DeepEqual(err, expected) { if !reflect.DeepEqual(err, expected) {
t.Errorf("StartContainer: Wrong error returned. Want %#v. Got %#v.", expected, err) t.Errorf("StartContainer: Wrong error returned. Want %#v. Got %#v.", expected, err)
} }
...@@ -1287,6 +1312,14 @@ func TestNoSuchContainerError(t *testing.T) { ...@@ -1287,6 +1312,14 @@ func TestNoSuchContainerError(t *testing.T) {
} }
} }
func TestNoSuchContainerErrorMessage(t *testing.T) {
var err = &NoSuchContainer{ID: "i345", Err: errors.New("some advanced error info")}
expected := "some advanced error info"
if got := err.Error(); got != expected {
t.Errorf("NoSuchContainer: wrong message. Want %q. Got %q.", expected, got)
}
}
func TestExportContainer(t *testing.T) { func TestExportContainer(t *testing.T) {
content := "exported container tar content" content := "exported container tar content"
out := stdoutMock{bytes.NewBufferString(content)} out := stdoutMock{bytes.NewBufferString(content)}
...@@ -1311,7 +1344,7 @@ func TestExportContainerViaUnixSocket(t *testing.T) { ...@@ -1311,7 +1344,7 @@ func TestExportContainerViaUnixSocket(t *testing.T) {
tempSocket := tempfile("export_socket") tempSocket := tempfile("export_socket")
defer os.Remove(tempSocket) defer os.Remove(tempSocket)
endpoint := "unix://" + tempSocket endpoint := "unix://" + tempSocket
u, _ := parseEndpoint(endpoint) u, _ := parseEndpoint(endpoint, false)
client := Client{ client := Client{
HTTPClient: http.DefaultClient, HTTPClient: http.DefaultClient,
endpoint: endpoint, endpoint: endpoint,
...@@ -1522,3 +1555,26 @@ func TestTopContainerWithPsArgs(t *testing.T) { ...@@ -1522,3 +1555,26 @@ func TestTopContainerWithPsArgs(t *testing.T) {
t.Errorf("TopContainer: Expected URI to have %q. Got %q.", expectedURI, fakeRT.requests[0].URL.String()) t.Errorf("TopContainer: Expected URI to have %q. Got %q.", expectedURI, fakeRT.requests[0].URL.String())
} }
} }
func TestRenameContainer(t *testing.T) {
fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK}
client := newTestClient(fakeRT)
opts := RenameContainerOptions{ID: "something_old", Name: "something_new"}
err := client.RenameContainer(opts)
if err != nil {
t.Fatal(err)
}
req := fakeRT.requests[0]
if req.Method != "POST" {
t.Errorf("RenameContainer: wrong HTTP method. Want %q. Got %q.", "POST", req.Method)
}
expectedURL, _ := url.Parse(client.getURL("/containers/something_old/rename?name=something_new"))
if gotPath := req.URL.Path; gotPath != expectedURL.Path {
t.Errorf("RenameContainer: Wrong path in request. Want %q. Got %q.", expectedURL.Path, gotPath)
}
expectedValues := expectedURL.Query()["name"]
actualValues := req.URL.Query()["name"]
if len(actualValues) != 1 || expectedValues[0] != actualValues[0] {
t.Errorf("RenameContainer: Wrong params in request. Want %q. Got %q.", expectedValues, actualValues)
}
}
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -182,8 +182,8 @@ func (eventState *eventMonitoringState) monitorEvents(c *Client) { ...@@ -182,8 +182,8 @@ func (eventState *eventMonitoringState) monitorEvents(c *Client) {
eventState.terminate() eventState.terminate()
return return
} }
eventState.updateLastSeen(ev)
go eventState.sendEvent(ev) go eventState.sendEvent(ev)
go eventState.updateLastSeen(ev)
case err = <-eventState.errC: case err = <-eventState.errC:
if err == ErrNoListeners { if err == ErrNoListeners {
eventState.terminate() eventState.terminate()
...@@ -227,7 +227,7 @@ func (eventState *eventMonitoringState) sendEvent(event *APIEvents) { ...@@ -227,7 +227,7 @@ func (eventState *eventMonitoringState) sendEvent(event *APIEvents) {
eventState.Add(1) eventState.Add(1)
defer eventState.Done() defer eventState.Done()
if eventState.isEnabled() { if eventState.isEnabled() {
if eventState.noListeners() { if len(eventState.listeners) == 0 {
eventState.errC <- ErrNoListeners eventState.errC <- ErrNoListeners
return return
} }
......
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -90,7 +90,7 @@ type ExecInspect struct { ...@@ -90,7 +90,7 @@ type ExecInspect struct {
// See http://goo.gl/8izrzI for more details // See http://goo.gl/8izrzI for more details
func (c *Client) CreateExec(opts CreateExecOptions) (*Exec, error) { func (c *Client) CreateExec(opts CreateExecOptions) (*Exec, error) {
path := fmt.Sprintf("/containers/%s/exec", opts.Container) path := fmt.Sprintf("/containers/%s/exec", opts.Container)
body, status, err := c.do("POST", path, opts) body, status, err := c.do("POST", path, opts, false)
if status == http.StatusNotFound { if status == http.StatusNotFound {
return nil, &NoSuchContainer{ID: opts.Container} return nil, &NoSuchContainer{ID: opts.Container}
} }
...@@ -119,7 +119,7 @@ func (c *Client) StartExec(id string, opts StartExecOptions) error { ...@@ -119,7 +119,7 @@ func (c *Client) StartExec(id string, opts StartExecOptions) error {
path := fmt.Sprintf("/exec/%s/start", id) path := fmt.Sprintf("/exec/%s/start", id)
if opts.Detach { if opts.Detach {
_, status, err := c.do("POST", path, opts) _, status, err := c.do("POST", path, opts, false)
if status == http.StatusNotFound { if status == http.StatusNotFound {
return &NoSuchExec{ID: id} return &NoSuchExec{ID: id}
} }
...@@ -143,7 +143,7 @@ func (c *Client) ResizeExecTTY(id string, height, width int) error { ...@@ -143,7 +143,7 @@ func (c *Client) ResizeExecTTY(id string, height, width int) error {
params.Set("w", strconv.Itoa(width)) params.Set("w", strconv.Itoa(width))
path := fmt.Sprintf("/exec/%s/resize?%s", id, params.Encode()) path := fmt.Sprintf("/exec/%s/resize?%s", id, params.Encode())
_, _, err := c.do("POST", path, nil) _, _, err := c.do("POST", path, nil, false)
return err return err
} }
...@@ -152,7 +152,7 @@ func (c *Client) ResizeExecTTY(id string, height, width int) error { ...@@ -152,7 +152,7 @@ func (c *Client) ResizeExecTTY(id string, height, width int) error {
// See http://goo.gl/ypQULN for more details // See http://goo.gl/ypQULN for more details
func (c *Client) InspectExec(id string) (*ExecInspect, error) { func (c *Client) InspectExec(id string) (*ExecInspect, error) {
path := fmt.Sprintf("/exec/%s/json", id) path := fmt.Sprintf("/exec/%s/json", id)
body, status, err := c.do("GET", path, nil) body, status, err := c.do("GET", path, nil, false)
if status == http.StatusNotFound { if status == http.StatusNotFound {
return nil, &NoSuchExec{ID: id} return nil, &NoSuchExec{ID: id}
} }
......
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -99,7 +99,7 @@ var ( ...@@ -99,7 +99,7 @@ var (
// See http://goo.gl/2rOLFF for more details. // See http://goo.gl/2rOLFF for more details.
func (c *Client) ListImages(opts ListImagesOptions) ([]APIImages, error) { func (c *Client) ListImages(opts ListImagesOptions) ([]APIImages, error) {
path := "/images/json?" + queryString(opts) path := "/images/json?" + queryString(opts)
body, _, err := c.do("GET", path, nil) body, _, err := c.do("GET", path, nil, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -115,7 +115,7 @@ func (c *Client) ListImages(opts ListImagesOptions) ([]APIImages, error) { ...@@ -115,7 +115,7 @@ func (c *Client) ListImages(opts ListImagesOptions) ([]APIImages, error) {
// //
// See http://goo.gl/2oJmNs for more details. // See http://goo.gl/2oJmNs for more details.
func (c *Client) ImageHistory(name string) ([]ImageHistory, error) { func (c *Client) ImageHistory(name string) ([]ImageHistory, error) {
body, status, err := c.do("GET", "/images/"+name+"/history", nil) body, status, err := c.do("GET", "/images/"+name+"/history", nil, false)
if status == http.StatusNotFound { if status == http.StatusNotFound {
return nil, ErrNoSuchImage return nil, ErrNoSuchImage
} }
...@@ -134,7 +134,29 @@ func (c *Client) ImageHistory(name string) ([]ImageHistory, error) { ...@@ -134,7 +134,29 @@ func (c *Client) ImageHistory(name string) ([]ImageHistory, error) {
// //
// See http://goo.gl/znj0wM for more details. // See http://goo.gl/znj0wM for more details.
func (c *Client) RemoveImage(name string) error { func (c *Client) RemoveImage(name string) error {
_, status, err := c.do("DELETE", "/images/"+name, nil) _, status, err := c.do("DELETE", "/images/"+name, nil, false)
if status == http.StatusNotFound {
return ErrNoSuchImage
}
return err
}
// RemoveImageOptions present the set of options available for removing an image
// from a registry.
//
// See http://goo.gl/6V48bF for more details.
type RemoveImageOptions struct {
Force bool `qs:"force"`
NoPrune bool `qs:"noprune"`
}
// RemoveImageExtended removes an image by its name or ID.
// Extra params can be passed, see RemoveImageOptions
//
// See http://goo.gl/znj0wM for more details.
func (c *Client) RemoveImageExtended(name string, opts RemoveImageOptions) error {
uri := fmt.Sprintf("/images/%s?%s", name, queryString(&opts))
_, status, err := c.do("DELETE", uri, nil, false)
if status == http.StatusNotFound { if status == http.StatusNotFound {
return ErrNoSuchImage return ErrNoSuchImage
} }
...@@ -145,7 +167,7 @@ func (c *Client) RemoveImage(name string) error { ...@@ -145,7 +167,7 @@ func (c *Client) RemoveImage(name string) error {
// //
// See http://goo.gl/Q112NY for more details. // See http://goo.gl/Q112NY for more details.
func (c *Client) InspectImage(name string) (*Image, error) { func (c *Client) InspectImage(name string) (*Image, error) {
body, status, err := c.do("GET", "/images/"+name+"/json", nil) body, status, err := c.do("GET", "/images/"+name+"/json", nil, false)
if status == http.StatusNotFound { if status == http.StatusNotFound {
return nil, ErrNoSuchImage return nil, ErrNoSuchImage
} }
...@@ -156,7 +178,7 @@ func (c *Client) InspectImage(name string) (*Image, error) { ...@@ -156,7 +178,7 @@ func (c *Client) InspectImage(name string) (*Image, error) {
var image Image var image Image
// if the caller elected to skip checking the server's version, assume it's the latest // if the caller elected to skip checking the server's version, assume it's the latest
if c.SkipServerVersionCheck || c.expectedAPIVersion.GreaterThanOrEqualTo(apiVersion1_12) { if c.SkipServerVersionCheck || c.expectedAPIVersion.GreaterThanOrEqualTo(apiVersion112) {
err = json.Unmarshal(body, &image) err = json.Unmarshal(body, &image)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -201,21 +223,6 @@ type PushImageOptions struct { ...@@ -201,21 +223,6 @@ type PushImageOptions struct {
RawJSONStream bool `qs:"-"` RawJSONStream bool `qs:"-"`
} }
// AuthConfiguration represents authentication options to use in the PushImage
// method. It represents the authentication in the Docker index server.
type AuthConfiguration struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Email string `json:"email,omitempty"`
ServerAddress string `json:"serveraddress,omitempty"`
}
// AuthConfigurations represents authentication options to use for the
// PushImage method accommodating the new X-Registry-Config header
type AuthConfigurations struct {
Configs map[string]AuthConfiguration `json:"configs"`
}
// PushImage pushes an image to a remote registry, logging progress to w. // PushImage pushes an image to a remote registry, logging progress to w.
// //
// An empty instance of AuthConfiguration may be used for unauthenticated // An empty instance of AuthConfiguration may be used for unauthenticated
...@@ -245,7 +252,7 @@ type PullImageOptions struct { ...@@ -245,7 +252,7 @@ type PullImageOptions struct {
RawJSONStream bool `qs:"-"` RawJSONStream bool `qs:"-"`
} }
// PullImage pulls an image from a remote registry, logging progress to w. // PullImage pulls an image from a remote registry, logging progress to opts.OutputStream.
// //
// See http://goo.gl/ACyYNS for more details. // See http://goo.gl/ACyYNS for more details.
func (c *Client) PullImage(opts PullImageOptions, auth AuthConfiguration) error { func (c *Client) PullImage(opts PullImageOptions, auth AuthConfiguration) error {
...@@ -333,6 +340,7 @@ func (c *Client) ImportImage(opts ImportImageOptions) error { ...@@ -333,6 +340,7 @@ func (c *Client) ImportImage(opts ImportImageOptions) error {
// http://goo.gl/tlPXPu. // http://goo.gl/tlPXPu.
type BuildImageOptions struct { type BuildImageOptions struct {
Name string `qs:"t"` Name string `qs:"t"`
Dockerfile string `qs:"dockerfile"`
NoCache bool `qs:"nocache"` NoCache bool `qs:"nocache"`
SuppressOutput bool `qs:"q"` SuppressOutput bool `qs:"q"`
RmTmpContainer bool `qs:"rm"` RmTmpContainer bool `qs:"rm"`
...@@ -395,7 +403,8 @@ func (c *Client) TagImage(name string, opts TagImageOptions) error { ...@@ -395,7 +403,8 @@ func (c *Client) TagImage(name string, opts TagImageOptions) error {
return ErrNoSuchImage return ErrNoSuchImage
} }
_, status, err := c.do("POST", fmt.Sprintf("/images/"+name+"/tag?%s", _, status, err := c.do("POST", fmt.Sprintf("/images/"+name+"/tag?%s",
queryString(&opts)), nil) queryString(&opts)), nil, false)
if status == http.StatusNotFound { if status == http.StatusNotFound {
return ErrNoSuchImage return ErrNoSuchImage
} }
...@@ -445,7 +454,7 @@ type APIImageSearch struct { ...@@ -445,7 +454,7 @@ type APIImageSearch struct {
// //
// See http://goo.gl/xI5lLZ for more details. // See http://goo.gl/xI5lLZ for more details.
func (c *Client) SearchImages(term string) ([]APIImageSearch, error) { func (c *Client) SearchImages(term string) ([]APIImageSearch, error) {
body, _, err := c.do("GET", "/images/search?term="+term, nil) body, _, err := c.do("GET", "/images/search?term="+term, nil, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -19,7 +19,7 @@ import ( ...@@ -19,7 +19,7 @@ import (
func newTestClient(rt *FakeRoundTripper) Client { func newTestClient(rt *FakeRoundTripper) Client {
endpoint := "http://localhost:4243" endpoint := "http://localhost:4243"
u, _ := parseEndpoint("http://localhost:4243") u, _ := parseEndpoint("http://localhost:4243", false)
client := Client{ client := Client{
HTTPClient: &http.Client{Transport: rt}, HTTPClient: &http.Client{Transport: rt},
endpoint: endpoint, endpoint: endpoint,
...@@ -208,6 +208,29 @@ func TestRemoveImageNotFound(t *testing.T) { ...@@ -208,6 +208,29 @@ func TestRemoveImageNotFound(t *testing.T) {
} }
} }
func TestRemoveImageExtended(t *testing.T) {
name := "test"
fakeRT := &FakeRoundTripper{message: "", status: http.StatusNoContent}
client := newTestClient(fakeRT)
err := client.RemoveImageExtended(name, RemoveImageOptions{Force: true, NoPrune: true})
if err != nil {
t.Fatal(err)
}
req := fakeRT.requests[0]
expectedMethod := "DELETE"
if req.Method != expectedMethod {
t.Errorf("RemoveImage(%q): Wrong HTTP method. Want %s. Got %s.", name, expectedMethod, req.Method)
}
u, _ := url.Parse(client.getURL("/images/" + name))
if req.URL.Path != u.Path {
t.Errorf("RemoveImage(%q): Wrong request path. Want %q. Got %q.", name, u.Path, req.URL.Path)
}
expectedQuery := "force=1&noprune=1"
if query := req.URL.Query().Encode(); query != expectedQuery {
t.Errorf("PushImage: Wrong query string. Want %q. Got %q.", expectedQuery, query)
}
}
func TestInspectImage(t *testing.T) { func TestInspectImage(t *testing.T) {
body := `{ body := `{
"id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", "id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
......
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
// //
// See http://goo.gl/BOZrF5 for more details. // See http://goo.gl/BOZrF5 for more details.
func (c *Client) Version() (*Env, error) { func (c *Client) Version() (*Env, error) {
body, _, err := c.do("GET", "/version", nil) body, _, err := c.do("GET", "/version", nil, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -28,7 +28,7 @@ func (c *Client) Version() (*Env, error) { ...@@ -28,7 +28,7 @@ func (c *Client) Version() (*Env, error) {
// //
// See http://goo.gl/wmqZsW for more details. // See http://goo.gl/wmqZsW for more details.
func (c *Client) Info() (*Env, error) { func (c *Client) Info() (*Env, error) {
body, _, err := c.do("GET", "/info", nil) body, _, err := c.do("GET", "/info", nil, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
// Copyright 2014 go-dockerclient authors. All rights reserved. // Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment