mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 03:11:40 +00:00
Really upgrade fsouza/go-dockerclient pkg to latest revision, so that we can have
Error and OOMKilled from docker ContainerStatus.
This commit is contained in:
parent
b489757b5a
commit
95e3efdad8
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -104,8 +104,8 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/fsouza/go-dockerclient",
|
||||
"Comment": "0.2.1-267-g15d2c6e",
|
||||
"Rev": "15d2c6e3eb670c545d0af0604d7f9aff3871af04"
|
||||
"Comment": "0.2.1-334-g9c377ff",
|
||||
"Rev": "9c377ffd9aed48a012adf1c3fd517fe98394120b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/ghodss/yaml",
|
||||
|
2
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/.travis.yml
generated
vendored
2
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/.travis.yml
generated
vendored
@ -1,6 +1,5 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.1.2
|
||||
- 1.2.2
|
||||
- 1.3.1
|
||||
- tip
|
||||
@ -11,3 +10,4 @@ install:
|
||||
- go get -d ./...
|
||||
script:
|
||||
- go test ./...
|
||||
- ./testing/bin/fmtpolice
|
||||
|
8
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/AUTHORS
generated
vendored
8
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/AUTHORS
generated
vendored
@ -12,6 +12,7 @@ cheneydeng <cheneydeng@qq.com>
|
||||
CMGS <ilskdw@gmail.com>
|
||||
Daniel, Dao Quang Minh <dqminh89@gmail.com>
|
||||
David Huie <dahuie@gmail.com>
|
||||
Dawn Chen <dawnchen@google.com>
|
||||
Ed <edrocksit@gmail.com>
|
||||
Eric Anderson <anderson@copperegg.com>
|
||||
Fabio Rehm <fgrehm@gmail.com>
|
||||
@ -19,6 +20,7 @@ Flavia Missi <flaviamissi@gmail.com>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Jari Kolehmainen <jari.kolehmainen@digia.com>
|
||||
Jason Wilder <jwilder@litl.com>
|
||||
Jawher Moussa <jawher.moussa@gmail.com>
|
||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||
Jeff Mitchell <jeffrey.mitchell@gmail.com>
|
||||
Jeffrey Hulten <jhulten@gmail.com>
|
||||
@ -26,11 +28,14 @@ Johan Euphrosine <proppy@google.com>
|
||||
Karan Misra <kidoman@gmail.com>
|
||||
Kim, Hirokuni <hirokuni.kim@kvh.co.jp>
|
||||
Lucas Clemente <lucas@clemente.io>
|
||||
Máximo Cuadros Ortiz <mcuadros@gmail.com>
|
||||
Mike Dillon <mike.dillon@synctree.com>
|
||||
Omeid Matten <public@omeid.me>
|
||||
Paul Morie <pmorie@gmail.com>
|
||||
Peter Jihoon Kim <raingrove@gmail.com>
|
||||
Philippe Lafoucrière <philippe.lafoucriere@tech-angels.com>
|
||||
Rafe Colton <r.colton@modcloth.com>
|
||||
Rafe Colton <rafael.colton@gmail.com>
|
||||
Rob Miller <rob@kalistra.com>
|
||||
Robert Williamson <williamson.robert@gmail.com>
|
||||
Salvador Gironès <salvadorgirones@gmail.com>
|
||||
Simon Eskildsen <sirup@sirupsen.com>
|
||||
@ -42,3 +47,4 @@ Summer Mousa <smousa@zenoss.com>
|
||||
Tarsis Azevedo <tarsis@corp.globo.com>
|
||||
Tim Schindler <tim@catalyst-zero.com>
|
||||
Wiliam Souza <wiliamsouza83@gmail.com>
|
||||
Ye Yin <eyniy@qq.com>
|
||||
|
2
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/README.markdown
generated
vendored
2
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/README.markdown
generated
vendored
@ -29,7 +29,7 @@ func main() {
|
||||
fmt.Println("Created: ", img.Created)
|
||||
fmt.Println("Size: ", img.Size)
|
||||
fmt.Println("VirtualSize: ", img.VirtualSize)
|
||||
fmt.Println("ParentId: ", img.ParentId)
|
||||
fmt.Println("ParentId: ", img.ParentID)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
144
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/build_test.go
generated
vendored
Normal file
144
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/build_test.go
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
)
|
||||
|
||||
func TestBuildImageMultipleContextsError(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
var buf bytes.Buffer
|
||||
opts := BuildImageOptions{
|
||||
Name: "testImage",
|
||||
NoCache: true,
|
||||
SuppressOutput: true,
|
||||
RmTmpContainer: true,
|
||||
ForceRmTmpContainer: true,
|
||||
InputStream: &buf,
|
||||
OutputStream: &buf,
|
||||
ContextDir: "testing/data",
|
||||
}
|
||||
err := client.BuildImage(opts)
|
||||
if err != ErrMultipleContexts {
|
||||
t.Errorf("BuildImage: providing both InputStream and ContextDir should produce an error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildImageContextDirDockerignoreParsing(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
var buf bytes.Buffer
|
||||
opts := BuildImageOptions{
|
||||
Name: "testImage",
|
||||
NoCache: true,
|
||||
SuppressOutput: true,
|
||||
RmTmpContainer: true,
|
||||
ForceRmTmpContainer: true,
|
||||
OutputStream: &buf,
|
||||
ContextDir: "testing/data",
|
||||
}
|
||||
err := client.BuildImage(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
reqBody := fakeRT.requests[0].Body
|
||||
tmpdir, err := unpackBodyTarball(reqBody)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := os.RemoveAll(tmpdir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
files, err := ioutil.ReadDir(tmpdir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
foundFiles := []string{}
|
||||
for _, file := range files {
|
||||
foundFiles = append(foundFiles, file.Name())
|
||||
}
|
||||
|
||||
expectedFiles := []string{
|
||||
".dockerignore",
|
||||
"Dockerfile",
|
||||
"barfile",
|
||||
"ca.pem",
|
||||
"cert.pem",
|
||||
"key.pem",
|
||||
"server.pem",
|
||||
"serverkey.pem",
|
||||
"symlink",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expectedFiles, foundFiles) {
|
||||
t.Errorf(
|
||||
"BuildImage: incorrect files sent in tarball to docker server\nexpected %+v, found %+v",
|
||||
expectedFiles, foundFiles,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildImageSendXRegistryConfig(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
var buf bytes.Buffer
|
||||
opts := BuildImageOptions{
|
||||
Name: "testImage",
|
||||
NoCache: true,
|
||||
SuppressOutput: true,
|
||||
RmTmpContainer: true,
|
||||
ForceRmTmpContainer: true,
|
||||
OutputStream: &buf,
|
||||
ContextDir: "testing/data",
|
||||
AuthConfigs: AuthConfigurations{
|
||||
Configs: map[string]AuthConfiguration{
|
||||
"quay.io": {
|
||||
Username: "foo",
|
||||
Password: "bar",
|
||||
Email: "baz",
|
||||
ServerAddress: "quay.io",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
encodedConfig := "eyJjb25maWdzIjp7InF1YXkuaW8iOnsidXNlcm5hbWUiOiJmb28iLCJwYXNzd29yZCI6ImJhciIsImVtYWlsIjoiYmF6Iiwic2VydmVyYWRkcmVzcyI6InF1YXkuaW8ifX19Cg=="
|
||||
|
||||
if err := client.BuildImage(opts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
xRegistryConfig := fakeRT.requests[0].Header["X-Registry-Config"][0]
|
||||
if xRegistryConfig != encodedConfig {
|
||||
t.Errorf(
|
||||
"BuildImage: X-Registry-Config not set currectly: expected %q, got %q",
|
||||
encodedConfig,
|
||||
xRegistryConfig,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func unpackBodyTarball(req io.ReadCloser) (tmpdir string, err error) {
|
||||
tmpdir, err = ioutil.TempDir("", "go-dockerclient-test")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = archive.Untar(req, tmpdir, &archive.TarOptions{
|
||||
Compression: archive.Uncompressed,
|
||||
NoLchown: true,
|
||||
})
|
||||
return
|
||||
}
|
7
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/change.go
generated
vendored
7
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/change.go
generated
vendored
@ -6,11 +6,18 @@ package docker
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ChangeType is a type for constants indicating the type of change
|
||||
// in a container
|
||||
type ChangeType int
|
||||
|
||||
const (
|
||||
// ChangeModify is the ChangeType for container modifications
|
||||
ChangeModify ChangeType = iota
|
||||
|
||||
// ChangeAdd is the ChangeType for additions to a container
|
||||
ChangeAdd
|
||||
|
||||
// ChangeDelete is the ChangeType for deletions from a container
|
||||
ChangeDelete
|
||||
)
|
||||
|
||||
|
166
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/client.go
generated
vendored
166
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/client.go
generated
vendored
@ -9,6 +9,8 @@ package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -32,22 +34,22 @@ var (
|
||||
// ErrConnectionRefused is returned when the client cannot connect to the given endpoint.
|
||||
ErrConnectionRefused = errors.New("cannot connect to Docker endpoint")
|
||||
|
||||
apiVersion_1_12, _ = NewApiVersion("1.12")
|
||||
apiVersion1_12, _ = NewAPIVersion("1.12")
|
||||
)
|
||||
|
||||
// ApiVersion is an internal representation of a version of the Remote API.
|
||||
type ApiVersion []int
|
||||
// APIVersion is an internal representation of a version of the Remote API.
|
||||
type APIVersion []int
|
||||
|
||||
// NewApiVersion returns an instance of ApiVersion for the given string.
|
||||
// NewAPIVersion returns an instance of APIVersion for the given string.
|
||||
//
|
||||
// The given string must be in the form <major>.<minor>.<patch>, where <major>,
|
||||
// <minor> and <patch> are integer numbers.
|
||||
func NewApiVersion(input string) (ApiVersion, error) {
|
||||
func NewAPIVersion(input string) (APIVersion, error) {
|
||||
if !strings.Contains(input, ".") {
|
||||
return nil, fmt.Errorf("Unable to parse version %q", input)
|
||||
}
|
||||
arr := strings.Split(input, ".")
|
||||
ret := make(ApiVersion, len(arr))
|
||||
ret := make(APIVersion, len(arr))
|
||||
var err error
|
||||
for i, val := range arr {
|
||||
ret[i], err = strconv.Atoi(val)
|
||||
@ -58,7 +60,7 @@ func NewApiVersion(input string) (ApiVersion, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (version ApiVersion) String() string {
|
||||
func (version APIVersion) String() string {
|
||||
var str string
|
||||
for i, val := range version {
|
||||
str += strconv.Itoa(val)
|
||||
@ -69,23 +71,27 @@ func (version ApiVersion) String() string {
|
||||
return str
|
||||
}
|
||||
|
||||
func (version ApiVersion) LessThan(other ApiVersion) bool {
|
||||
// LessThan is a function for comparing APIVersion structs
|
||||
func (version APIVersion) LessThan(other APIVersion) bool {
|
||||
return version.compare(other) < 0
|
||||
}
|
||||
|
||||
func (version ApiVersion) LessThanOrEqualTo(other ApiVersion) bool {
|
||||
// LessThanOrEqualTo is a function for comparing APIVersion structs
|
||||
func (version APIVersion) LessThanOrEqualTo(other APIVersion) bool {
|
||||
return version.compare(other) <= 0
|
||||
}
|
||||
|
||||
func (version ApiVersion) GreaterThan(other ApiVersion) bool {
|
||||
// GreaterThan is a function for comparing APIVersion structs
|
||||
func (version APIVersion) GreaterThan(other APIVersion) bool {
|
||||
return version.compare(other) > 0
|
||||
}
|
||||
|
||||
func (version ApiVersion) GreaterThanOrEqualTo(other ApiVersion) bool {
|
||||
// GreaterThanOrEqualTo is a function for comparing APIVersion structs
|
||||
func (version APIVersion) GreaterThanOrEqualTo(other APIVersion) bool {
|
||||
return version.compare(other) >= 0
|
||||
}
|
||||
|
||||
func (version ApiVersion) compare(other ApiVersion) int {
|
||||
func (version APIVersion) compare(other APIVersion) int {
|
||||
for i, v := range version {
|
||||
if i <= len(other)-1 {
|
||||
otherVersion := other[i]
|
||||
@ -111,13 +117,14 @@ func (version ApiVersion) compare(other ApiVersion) int {
|
||||
type Client struct {
|
||||
SkipServerVersionCheck bool
|
||||
HTTPClient *http.Client
|
||||
TLSConfig *tls.Config
|
||||
|
||||
endpoint string
|
||||
endpointURL *url.URL
|
||||
eventMonitor *eventMonitoringState
|
||||
requestedApiVersion ApiVersion
|
||||
serverApiVersion ApiVersion
|
||||
expectedApiVersion ApiVersion
|
||||
requestedAPIVersion APIVersion
|
||||
serverAPIVersion APIVersion
|
||||
expectedAPIVersion APIVersion
|
||||
}
|
||||
|
||||
// NewClient returns a Client instance ready for communication with the given
|
||||
@ -132,6 +139,18 @@ func NewClient(endpoint string) (*Client, error) {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// NewTLSClient returns a Client instance ready for TLS communications with the givens
|
||||
// server endpoint, key and certificates . It will use the latest remote API version
|
||||
// available in the server.
|
||||
func NewTLSClient(endpoint string, cert, key, ca string) (*Client, error) {
|
||||
client, err := NewVersionnedTLSClient(endpoint, cert, key, ca, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.SkipServerVersionCheck = true
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// NewVersionedClient returns a Client instance ready for communication with
|
||||
// the given server endpoint, using a specific remote API version.
|
||||
func NewVersionedClient(endpoint string, apiVersionString string) (*Client, error) {
|
||||
@ -139,9 +158,9 @@ func NewVersionedClient(endpoint string, apiVersionString string) (*Client, erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var requestedApiVersion ApiVersion
|
||||
var requestedAPIVersion APIVersion
|
||||
if strings.Contains(apiVersionString, ".") {
|
||||
requestedApiVersion, err = NewApiVersion(apiVersionString)
|
||||
requestedAPIVersion, err = NewAPIVersion(apiVersionString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -151,23 +170,74 @@ func NewVersionedClient(endpoint string, apiVersionString string) (*Client, erro
|
||||
endpoint: endpoint,
|
||||
endpointURL: u,
|
||||
eventMonitor: new(eventMonitoringState),
|
||||
requestedApiVersion: requestedApiVersion,
|
||||
requestedAPIVersion: requestedAPIVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) checkApiVersion() error {
|
||||
serverApiVersionString, err := c.getServerApiVersionString()
|
||||
// NewVersionnedTLSClient returns a Client instance ready for TLS communications with the givens
|
||||
// server endpoint, key and certificates, using a specific remote API version.
|
||||
func NewVersionnedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) {
|
||||
u, err := parseEndpoint(endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
c.serverApiVersion, err = NewApiVersion(serverApiVersionString)
|
||||
var requestedAPIVersion APIVersion
|
||||
if strings.Contains(apiVersionString, ".") {
|
||||
requestedAPIVersion, err = NewAPIVersion(apiVersionString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if cert == "" || key == "" {
|
||||
return nil, errors.New("Both cert and key path are required")
|
||||
}
|
||||
tlsCert, err := tls.LoadX509KeyPair(cert, key)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if c.requestedApiVersion == nil {
|
||||
c.expectedApiVersion = c.serverApiVersion
|
||||
tlsConfig := &tls.Config{Certificates: []tls.Certificate{tlsCert}}
|
||||
if ca == "" {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
} else {
|
||||
c.expectedApiVersion = c.requestedApiVersion
|
||||
cert, err := ioutil.ReadFile(ca)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
caPool := x509.NewCertPool()
|
||||
if !caPool.AppendCertsFromPEM(cert) {
|
||||
return nil, errors.New("Could not add RootCA pem")
|
||||
}
|
||||
tlsConfig.RootCAs = caPool
|
||||
}
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Client{
|
||||
HTTPClient: &http.Client{Transport: tr},
|
||||
TLSConfig: tlsConfig,
|
||||
endpoint: endpoint,
|
||||
endpointURL: u,
|
||||
eventMonitor: new(eventMonitoringState),
|
||||
requestedAPIVersion: requestedAPIVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) checkAPIVersion() error {
|
||||
serverAPIVersionString, err := c.getServerAPIVersionString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.serverAPIVersion, err = NewAPIVersion(serverAPIVersionString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.requestedAPIVersion == nil {
|
||||
c.expectedAPIVersion = c.serverAPIVersion
|
||||
} else {
|
||||
c.expectedAPIVersion = c.requestedAPIVersion
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -187,7 +257,7 @@ func (c *Client) Ping() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) getServerApiVersionString() (version string, err error) {
|
||||
func (c *Client) getServerAPIVersionString() (version string, err error) {
|
||||
body, status, err := c.do("GET", "/version", nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -213,8 +283,8 @@ 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 path != "/version" && !c.SkipServerVersionCheck && c.expectedAPIVersion == nil {
|
||||
err := c.checkAPIVersion()
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
@ -268,8 +338,8 @@ func (c *Client) stream(method, path string, setRawTerminal, rawJSONStream bool,
|
||||
if (method == "POST" || method == "PUT") && in == nil {
|
||||
in = bytes.NewReader(nil)
|
||||
}
|
||||
if path != "/version" && !c.SkipServerVersionCheck && c.expectedApiVersion == nil {
|
||||
err := c.checkApiVersion()
|
||||
if path != "/version" && !c.SkipServerVersionCheck && c.expectedAPIVersion == nil {
|
||||
err := c.checkAPIVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -357,8 +427,8 @@ func (c *Client) stream(method, path string, setRawTerminal, rawJSONStream bool,
|
||||
}
|
||||
|
||||
func (c *Client) hijack(method, path string, success chan struct{}, setRawTerminal bool, in io.Reader, stderr, stdout io.Writer, data interface{}) error {
|
||||
if path != "/version" && !c.SkipServerVersionCheck && c.expectedApiVersion == nil {
|
||||
err := c.checkApiVersion()
|
||||
if path != "/version" && !c.SkipServerVersionCheck && c.expectedAPIVersion == nil {
|
||||
err := c.checkAPIVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -434,11 +504,10 @@ func (c *Client) getURL(path string) string {
|
||||
urlStr = ""
|
||||
}
|
||||
|
||||
if c.requestedApiVersion != nil {
|
||||
return fmt.Sprintf("%s/v%s%s", urlStr, c.requestedApiVersion, path)
|
||||
} else {
|
||||
return fmt.Sprintf("%s%s", urlStr, path)
|
||||
if c.requestedAPIVersion != nil {
|
||||
return fmt.Sprintf("%s/v%s%s", urlStr, c.requestedAPIVersion, path)
|
||||
}
|
||||
return fmt.Sprintf("%s%s", urlStr, path)
|
||||
}
|
||||
|
||||
type jsonMessage struct {
|
||||
@ -495,6 +564,12 @@ func queryString(opts interface{}) string {
|
||||
items.Add(key, string(b))
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if len(v.MapKeys()) > 0 {
|
||||
if b, err := json.Marshal(v.Interface()); err == nil {
|
||||
items.Add(key, string(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return items.Encode()
|
||||
@ -520,7 +595,22 @@ func parseEndpoint(endpoint string) (*url.URL, error) {
|
||||
return nil, ErrInvalidEndpoint
|
||||
}
|
||||
if u.Scheme == "tcp" {
|
||||
u.Scheme = "http"
|
||||
_, port, err := net.SplitHostPort(u.Host)
|
||||
if err != nil {
|
||||
if e, ok := err.(*net.AddrError); ok {
|
||||
if e.Err == "missing port in address" {
|
||||
return u, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrInvalidEndpoint
|
||||
}
|
||||
|
||||
number, err := strconv.ParseInt(port, 10, 64)
|
||||
if err == nil && number == 2376 {
|
||||
u.Scheme = "https"
|
||||
} else {
|
||||
u.Scheme = "http"
|
||||
}
|
||||
}
|
||||
if u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "unix" {
|
||||
return nil, ErrInvalidEndpoint
|
||||
|
98
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/client_test.go
generated
vendored
98
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/client_test.go
generated
vendored
@ -39,8 +39,32 @@ func TestNewAPIClient(t *testing.T) {
|
||||
if !client.SkipServerVersionCheck {
|
||||
t.Error("Expected SkipServerVersionCheck to be true, got false")
|
||||
}
|
||||
if client.requestedApiVersion != nil {
|
||||
t.Errorf("Expected requestedApiVersion to be nil, got %#v.", client.requestedApiVersion)
|
||||
if client.requestedAPIVersion != nil {
|
||||
t.Errorf("Expected requestedAPIVersion to be nil, got %#v.", client.requestedAPIVersion)
|
||||
}
|
||||
}
|
||||
|
||||
func newTLSClient(endpoint string) (*Client, error) {
|
||||
return NewTLSClient(endpoint,
|
||||
"testing/data/cert.pem",
|
||||
"testing/data/key.pem",
|
||||
"testing/data/ca.pem")
|
||||
}
|
||||
|
||||
func TestNewTSLAPIClient(t *testing.T) {
|
||||
endpoint := "https://localhost:4243"
|
||||
client, err := newTLSClient(endpoint)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if client.endpoint != endpoint {
|
||||
t.Errorf("Expected endpoint %s. Got %s.", endpoint, client.endpoint)
|
||||
}
|
||||
if !client.SkipServerVersionCheck {
|
||||
t.Error("Expected SkipServerVersionCheck to be true, got false")
|
||||
}
|
||||
if client.requestedAPIVersion != nil {
|
||||
t.Errorf("Expected requestedAPIVersion to be nil, got %#v.", client.requestedAPIVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,14 +80,45 @@ func TestNewVersionedClient(t *testing.T) {
|
||||
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)
|
||||
if reqVersion := client.requestedAPIVersion.String(); reqVersion != "1.12" {
|
||||
t.Errorf("Wrong requestAPIVersion. Want %q. Got %q.", "1.12", reqVersion)
|
||||
}
|
||||
if client.SkipServerVersionCheck {
|
||||
t.Error("Expected SkipServerVersionCheck to be false, got true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTLSVersionedClient(t *testing.T) {
|
||||
certPath := "testing/data/cert.pem"
|
||||
keyPath := "testing/data/key.pem"
|
||||
caPath := "testing/data/ca.pem"
|
||||
endpoint := "https://localhost:4243"
|
||||
client, err := NewVersionnedTLSClient(endpoint, certPath, keyPath, caPath, "1.14")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if client.endpoint != endpoint {
|
||||
t.Errorf("Expected endpoint %s. Got %s.", endpoint, client.endpoint)
|
||||
}
|
||||
if reqVersion := client.requestedAPIVersion.String(); reqVersion != "1.14" {
|
||||
t.Errorf("Wrong requestAPIVersion. Want %q. Got %q.", "1.14", reqVersion)
|
||||
}
|
||||
if client.SkipServerVersionCheck {
|
||||
t.Error("Expected SkipServerVersionCheck to be false, got true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTLSVersionedClientInvalidCA(t *testing.T) {
|
||||
certPath := "testing/data/cert.pem"
|
||||
keyPath := "testing/data/key.pem"
|
||||
caPath := "testing/data/key.pem"
|
||||
endpoint := "https://localhost:4243"
|
||||
_, err := NewVersionnedTLSClient(endpoint, certPath, keyPath, caPath, "1.14")
|
||||
if err == nil {
|
||||
t.Errorf("Expected invalid ca at %s", caPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClientInvalidEndpoint(t *testing.T) {
|
||||
cases := []string{
|
||||
"htp://localhost:3243", "http://localhost:a", "localhost:8080",
|
||||
@ -81,6 +136,28 @@ func TestNewClientInvalidEndpoint(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTLSClient2376(t *testing.T) {
|
||||
var tests = []struct {
|
||||
endpoint string
|
||||
expected string
|
||||
}{
|
||||
{"tcp://localhost:2376", "https"},
|
||||
{"tcp://localhost:2375", "http"},
|
||||
{"tcp://localhost:4000", "http"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
client, err := newTLSClient(tt.endpoint)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
got := client.endpointURL.Scheme
|
||||
if got != tt.expected {
|
||||
t.Errorf("endpointURL.Scheme: Got %s. Want %s.", got, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetURL(t *testing.T) {
|
||||
var tests = []struct {
|
||||
endpoint string
|
||||
@ -129,6 +206,7 @@ func TestQueryString(t *testing.T) {
|
||||
{ListContainersOptions{All: true}, "all=1"},
|
||||
{ListContainersOptions{Before: "something"}, "before=something"},
|
||||
{ListContainersOptions{Before: "something", Since: "other"}, "before=something&since=other"},
|
||||
{ListContainersOptions{Filters: map[string][]string{"status": {"paused", "running"}}}, "filters=%7B%22status%22%3A%5B%22paused%22%2C%22running%22%5D%7D"},
|
||||
{dumb{X: 10, Y: 10.35000}, "x=10&y=10.35"},
|
||||
{dumb{W: v, X: 10, Y: 10.35000}, f32QueryString},
|
||||
{dumb{X: 10, Y: 10.35000, Z: 10}, "x=10&y=10.35&zee=10"},
|
||||
@ -147,7 +225,7 @@ func TestQueryString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewApiVersionFailures(t *testing.T) {
|
||||
func TestNewAPIVersionFailures(t *testing.T) {
|
||||
var tests = []struct {
|
||||
input string
|
||||
expectedError string
|
||||
@ -156,17 +234,17 @@ func TestNewApiVersionFailures(t *testing.T) {
|
||||
{"1.0-beta", `Unable to parse version "1.0-beta": "0-beta" is not an integer`},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
v, err := NewApiVersion(tt.input)
|
||||
v, err := NewAPIVersion(tt.input)
|
||||
if v != nil {
|
||||
t.Errorf("Expected <nil> version, got %v.", v)
|
||||
}
|
||||
if err.Error() != tt.expectedError {
|
||||
t.Errorf("NewApiVersion(%q): wrong error. Want %q. Got %q", tt.input, tt.expectedError, err.Error())
|
||||
t.Errorf("NewAPIVersion(%q): wrong error. Want %q. Got %q", tt.input, tt.expectedError, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApiVersions(t *testing.T) {
|
||||
func TestAPIVersions(t *testing.T) {
|
||||
var tests = []struct {
|
||||
a string
|
||||
b string
|
||||
@ -192,8 +270,8 @@ func TestApiVersions(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
a, _ := NewApiVersion(tt.a)
|
||||
b, _ := NewApiVersion(tt.b)
|
||||
a, _ := NewAPIVersion(tt.a)
|
||||
b, _ := NewAPIVersion(tt.b)
|
||||
|
||||
if tt.expectedALessThanB && !a.LessThan(b) {
|
||||
t.Errorf("Expected %#v < %#v", a, b)
|
||||
|
65
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/container.go
generated
vendored
65
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/container.go
generated
vendored
@ -18,15 +18,17 @@ import (
|
||||
|
||||
// ListContainersOptions specify parameters to the ListContainers function.
|
||||
//
|
||||
// See http://goo.gl/XqtcyU for more details.
|
||||
// See http://goo.gl/6Y4Gz7 for more details.
|
||||
type ListContainersOptions struct {
|
||||
All bool
|
||||
Size bool
|
||||
Limit int
|
||||
Since string
|
||||
Before string
|
||||
All bool
|
||||
Size bool
|
||||
Limit int
|
||||
Since string
|
||||
Before string
|
||||
Filters map[string][]string
|
||||
}
|
||||
|
||||
// APIPort is a type that represents a port mapping returned by the Docker API
|
||||
type APIPort struct {
|
||||
PrivatePort int64 `json:"PrivatePort,omitempty" yaml:"PrivatePort,omitempty"`
|
||||
PublicPort int64 `json:"PublicPort,omitempty" yaml:"PublicPort,omitempty"`
|
||||
@ -51,7 +53,7 @@ type APIContainers struct {
|
||||
|
||||
// ListContainers returns a slice of containers matching the given criteria.
|
||||
//
|
||||
// See http://goo.gl/XqtcyU for more details.
|
||||
// See http://goo.gl/6Y4Gz7 for more details.
|
||||
func (c *Client) ListContainers(opts ListContainersOptions) ([]APIContainers, error) {
|
||||
path := "/containers/json?" + queryString(opts)
|
||||
body, _, err := c.do("GET", path, nil)
|
||||
@ -88,8 +90,10 @@ func (p Port) Proto() string {
|
||||
type State struct {
|
||||
Running bool `json:"Running,omitempty" yaml:"Running,omitempty"`
|
||||
Paused bool `json:"Paused,omitempty" yaml:"Paused,omitempty"`
|
||||
OOMKilled bool `json:"OOMKilled,omitempty" yaml:"OOMKilled,omitempty"`
|
||||
Pid int `json:"Pid,omitempty" yaml:"Pid,omitempty"`
|
||||
ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty"`
|
||||
Error string `json:"Error,omitempty" yaml:"Error,omitempty"`
|
||||
StartedAt time.Time `json:"StartedAt,omitempty" yaml:"StartedAt,omitempty"`
|
||||
FinishedAt time.Time `json:"FinishedAt,omitempty" yaml:"FinishedAt,omitempty"`
|
||||
}
|
||||
@ -105,13 +109,18 @@ func (s *State) String() string {
|
||||
return fmt.Sprintf("Exit %d", s.ExitCode)
|
||||
}
|
||||
|
||||
// PortBinding represents the host/container port mapping as returned in the
|
||||
// `docker inspect` json
|
||||
type PortBinding struct {
|
||||
HostIp string `json:"HostIP,omitempty" yaml:"HostIP,omitempty"`
|
||||
HostIP string `json:"HostIP,omitempty" yaml:"HostIP,omitempty"`
|
||||
HostPort string `json:"HostPort,omitempty" yaml:"HostPort,omitempty"`
|
||||
}
|
||||
|
||||
// PortMapping represents a deprecated field in the `docker inspect` output,
|
||||
// and its value as found in NetworkSettings should always be nil
|
||||
type PortMapping map[string]string
|
||||
|
||||
// NetworkSettings contains network-related information about a container
|
||||
type NetworkSettings struct {
|
||||
IPAddress string `json:"IPAddress,omitempty" yaml:"IPAddress,omitempty"`
|
||||
IPPrefixLen int `json:"IPPrefixLen,omitempty" yaml:"IPPrefixLen,omitempty"`
|
||||
@ -121,6 +130,8 @@ type NetworkSettings struct {
|
||||
Ports map[Port][]PortBinding `json:"Ports,omitempty" yaml:"Ports,omitempty"`
|
||||
}
|
||||
|
||||
// PortMappingAPI translates the port mappings as contained in NetworkSettings
|
||||
// into the format in which they would appear when returned by the API
|
||||
func (settings *NetworkSettings) PortMappingAPI() []APIPort {
|
||||
var mapping []APIPort
|
||||
for port, bindings := range settings.Ports {
|
||||
@ -139,7 +150,7 @@ func (settings *NetworkSettings) PortMappingAPI() []APIPort {
|
||||
PrivatePort: int64(p),
|
||||
PublicPort: int64(h),
|
||||
Type: port.Proto(),
|
||||
IP: binding.HostIp,
|
||||
IP: binding.HostIP,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -154,14 +165,17 @@ func parsePort(rawPort string) (int, error) {
|
||||
return int(port), nil
|
||||
}
|
||||
|
||||
// Config is the list of configuration options used when creating a container.
|
||||
// Config does not the options that are specific to starting a container on a
|
||||
// given host. Those are contained in HostConfig
|
||||
type Config struct {
|
||||
Hostname string `json:"Hostname,omitempty" yaml:"Hostname,omitempty"`
|
||||
Domainname string `json:"Domainname,omitempty" yaml:"Domainname,omitempty"`
|
||||
User string `json:"User,omitempty" yaml:"User,omitempty"`
|
||||
Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty"`
|
||||
MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty"`
|
||||
CpuShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty"`
|
||||
CpuSet string `json:"CpuSet,omitempty" yaml:"CpuSet,omitempty"`
|
||||
CPUShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty"`
|
||||
CPUSet string `json:"Cpuset,omitempty" yaml:"Cpuset,omitempty"`
|
||||
AttachStdin bool `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty"`
|
||||
AttachStdout bool `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty"`
|
||||
AttachStderr bool `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty"`
|
||||
@ -172,7 +186,7 @@ type Config struct {
|
||||
StdinOnce bool `json:"StdinOnce,omitempty" yaml:"StdinOnce,omitempty"`
|
||||
Env []string `json:"Env,omitempty" yaml:"Env,omitempty"`
|
||||
Cmd []string `json:"Cmd,omitempty" yaml:"Cmd,omitempty"`
|
||||
Dns []string `json:"Dns,omitempty" yaml:"Dns,omitempty"` // For Docker API v1.9 and below only
|
||||
DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty"` // For Docker API v1.9 and below only
|
||||
Image string `json:"Image,omitempty" yaml:"Image,omitempty"`
|
||||
Volumes map[string]struct{} `json:"Volumes,omitempty" yaml:"Volumes,omitempty"`
|
||||
VolumesFrom string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty"`
|
||||
@ -181,6 +195,8 @@ type Config struct {
|
||||
NetworkDisabled bool `json:"NetworkDisabled,omitempty" yaml:"NetworkDisabled,omitempty"`
|
||||
}
|
||||
|
||||
// Container is the type encompasing everything about a container - its config,
|
||||
// hostconfig, etc.
|
||||
type Container struct {
|
||||
ID string `json:"Id" yaml:"Id"`
|
||||
|
||||
@ -249,10 +265,11 @@ func (c *Client) ContainerChanges(id string) ([]Change, error) {
|
||||
|
||||
// CreateContainerOptions specify parameters to the CreateContainer function.
|
||||
//
|
||||
// See http://goo.gl/mErxNp for more details.
|
||||
// See http://goo.gl/2xxQQK for more details.
|
||||
type CreateContainerOptions struct {
|
||||
Name string
|
||||
Config *Config `qs:"-"`
|
||||
Name string
|
||||
Config *Config `qs:"-"`
|
||||
HostConfig *HostConfig
|
||||
}
|
||||
|
||||
// CreateContainer creates a new container, returning the container instance,
|
||||
@ -261,7 +278,14 @@ type CreateContainerOptions struct {
|
||||
// See http://goo.gl/mErxNp for more details.
|
||||
func (c *Client) CreateContainer(opts CreateContainerOptions) (*Container, error) {
|
||||
path := "/containers/create?" + queryString(opts)
|
||||
body, status, err := c.do("POST", path, opts.Config)
|
||||
body, status, err := c.do("POST", path, struct {
|
||||
*Config
|
||||
HostConfig *HostConfig `json:"HostConfig,omitempty" yaml:"HostConfig,omitempty"`
|
||||
}{
|
||||
opts.Config,
|
||||
opts.HostConfig,
|
||||
})
|
||||
|
||||
if status == http.StatusNotFound {
|
||||
return nil, ErrNoSuchImage
|
||||
}
|
||||
@ -279,6 +303,8 @@ func (c *Client) CreateContainer(opts CreateContainerOptions) (*Container, error
|
||||
return &container, nil
|
||||
}
|
||||
|
||||
// KeyValuePair is a type for generic key/value pairs as used in the Lxc
|
||||
// configuration
|
||||
type KeyValuePair struct {
|
||||
Key string `json:"Key,omitempty" yaml:"Key,omitempty"`
|
||||
Value string `json:"Value,omitempty" yaml:"Value,omitempty"`
|
||||
@ -315,6 +341,8 @@ func NeverRestart() RestartPolicy {
|
||||
return RestartPolicy{Name: "no"}
|
||||
}
|
||||
|
||||
// HostConfig contains the container options related to starting a container on
|
||||
// a given host
|
||||
type HostConfig struct {
|
||||
Binds []string `json:"Binds,omitempty" yaml:"Binds,omitempty"`
|
||||
CapAdd []string `json:"CapAdd,omitempty" yaml:"CapAdd,omitempty"`
|
||||
@ -325,8 +353,9 @@ type HostConfig struct {
|
||||
PortBindings map[Port][]PortBinding `json:"PortBindings,omitempty" yaml:"PortBindings,omitempty"`
|
||||
Links []string `json:"Links,omitempty" yaml:"Links,omitempty"`
|
||||
PublishAllPorts bool `json:"PublishAllPorts,omitempty" yaml:"PublishAllPorts,omitempty"`
|
||||
Dns []string `json:"Dns,omitempty" yaml:"Dns,omitempty"` // For Docker API v1.10 and above only
|
||||
DnsSearch []string `json:"DnsSearch,omitempty" yaml:"DnsSearch,omitempty"`
|
||||
DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty"` // For Docker API v1.10 and above only
|
||||
DNSSearch []string `json:"DnsSearch,omitempty" yaml:"DnsSearch,omitempty"`
|
||||
ExtraHosts []string `json:"ExtraHosts,omitempty" yaml:"ExtraHosts,omitempty"`
|
||||
VolumesFrom []string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty"`
|
||||
NetworkMode string `json:"NetworkMode,omitempty" yaml:"NetworkMode,omitempty"`
|
||||
RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty" yaml:"RestartPolicy,omitempty"`
|
||||
|
31
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/container_test.go
generated
vendored
31
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/container_test.go
generated
vendored
@ -102,6 +102,14 @@ func TestListContainersParams(t *testing.T) {
|
||||
ListContainersOptions{All: true, Limit: 10, Since: "adf9983", Before: "abdeef"},
|
||||
map[string][]string{"all": {"1"}, "limit": {"10"}, "since": {"adf9983"}, "before": {"abdeef"}},
|
||||
},
|
||||
{
|
||||
ListContainersOptions{Filters: map[string][]string{"status": {"paused", "running"}}},
|
||||
map[string][]string{"filters": {"{\"status\":[\"paused\",\"running\"]}"}},
|
||||
},
|
||||
{
|
||||
ListContainersOptions{All: true, Filters: map[string][]string{"exited": {"0"}, "status": {"exited"}}},
|
||||
map[string][]string{"all": {"1"}, "filters": {"{\"exited\":[\"0\"],\"status\":[\"exited\"]}"}},
|
||||
},
|
||||
}
|
||||
fakeRT := &FakeRoundTripper{message: "[]", status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
@ -440,6 +448,27 @@ func TestCreateContainerImageNotFound(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateContainerWithHostConfig(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "{}", status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
config := Config{}
|
||||
hostConfig := HostConfig{PublishAllPorts: true}
|
||||
opts := CreateContainerOptions{Name: "TestCreateContainerWithHostConfig", Config: &config, HostConfig: &hostConfig}
|
||||
_, err := client.CreateContainer(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req := fakeRT.requests[0]
|
||||
var gotBody map[string]interface{}
|
||||
err = json.NewDecoder(req.Body).Decode(&gotBody)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := gotBody["HostConfig"]; !ok {
|
||||
t.Errorf("CreateContainer: wrong body. HostConfig was not serialized")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartContainer(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "", status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
@ -1251,7 +1280,7 @@ func TestLogsNoContainer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNoSuchContainerError(t *testing.T) {
|
||||
var err error = &NoSuchContainer{ID: "i345"}
|
||||
var err = &NoSuchContainer{ID: "i345"}
|
||||
expected := "No such container: i345"
|
||||
if got := err.Error(); got != expected {
|
||||
t.Errorf("NoSuchContainer: wrong message. Want %q. Got %q.", expected, got)
|
||||
|
41
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/event.go
generated
vendored
41
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/event.go
generated
vendored
@ -5,6 +5,7 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -49,6 +50,11 @@ var (
|
||||
// ErrListenerAlreadyExists is the error returned when the listerner already
|
||||
// exists.
|
||||
ErrListenerAlreadyExists = errors.New("listener already exists for docker events")
|
||||
|
||||
// EOFEvent is sent when the event listener receives an EOF error.
|
||||
EOFEvent = &APIEvents{
|
||||
Status: "EOF",
|
||||
}
|
||||
)
|
||||
|
||||
// AddEventListener adds a new listener to container events in the Docker API.
|
||||
@ -111,6 +117,16 @@ func (eventState *eventMonitoringState) removeListener(listener chan<- *APIEvent
|
||||
return nil
|
||||
}
|
||||
|
||||
func (eventState *eventMonitoringState) closeListeners() {
|
||||
eventState.Lock()
|
||||
defer eventState.Unlock()
|
||||
for _, l := range eventState.listeners {
|
||||
close(l)
|
||||
eventState.Add(-1)
|
||||
}
|
||||
eventState.listeners = nil
|
||||
}
|
||||
|
||||
func listenerExists(a chan<- *APIEvents, list *[]chan<- *APIEvents) bool {
|
||||
for _, b := range *list {
|
||||
if b == a {
|
||||
@ -152,7 +168,7 @@ func (eventState *eventMonitoringState) monitorEvents(c *Client) {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
if err = eventState.connectWithRetry(c); err != nil {
|
||||
eventState.terminate(err)
|
||||
eventState.terminate()
|
||||
}
|
||||
for eventState.isEnabled() {
|
||||
timeout := time.After(100 * time.Millisecond)
|
||||
@ -161,11 +177,16 @@ func (eventState *eventMonitoringState) monitorEvents(c *Client) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if ev == EOFEvent {
|
||||
eventState.closeListeners()
|
||||
eventState.terminate()
|
||||
return
|
||||
}
|
||||
go eventState.sendEvent(ev)
|
||||
go eventState.updateLastSeen(ev)
|
||||
case err = <-eventState.errC:
|
||||
if err == ErrNoListeners {
|
||||
eventState.terminate(nil)
|
||||
eventState.terminate()
|
||||
return
|
||||
} else if err != nil {
|
||||
defer func() { go eventState.monitorEvents(c) }()
|
||||
@ -225,7 +246,7 @@ func (eventState *eventMonitoringState) updateLastSeen(e *APIEvents) {
|
||||
}
|
||||
}
|
||||
|
||||
func (eventState *eventMonitoringState) terminate(err error) {
|
||||
func (eventState *eventMonitoringState) terminate() {
|
||||
eventState.disableEventMonitoring()
|
||||
}
|
||||
|
||||
@ -240,7 +261,13 @@ func (c *Client) eventHijack(startTime int64, eventChan chan *APIEvents, errChan
|
||||
protocol = "tcp"
|
||||
address = c.endpointURL.Host
|
||||
}
|
||||
dial, err := net.Dial(protocol, address)
|
||||
var dial net.Conn
|
||||
var err error
|
||||
if c.TLSConfig == nil {
|
||||
dial, err = net.Dial(protocol, address)
|
||||
} else {
|
||||
dial, err = tls.Dial(protocol, address, c.TLSConfig)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -261,6 +288,10 @@ func (c *Client) eventHijack(startTime int64, eventChan chan *APIEvents, errChan
|
||||
var event APIEvents
|
||||
if err = decoder.Decode(&event); err != nil {
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
if c.eventMonitor.isEnabled() {
|
||||
// Signal that we're exiting.
|
||||
eventChan <- EOFEvent
|
||||
}
|
||||
break
|
||||
}
|
||||
errChan <- err
|
||||
@ -271,7 +302,7 @@ func (c *Client) eventHijack(startTime int64, eventChan chan *APIEvents, errChan
|
||||
if !c.eventMonitor.isEnabled() {
|
||||
return
|
||||
}
|
||||
c.eventMonitor.C <- &event
|
||||
eventChan <- &event
|
||||
}
|
||||
}(res, conn)
|
||||
return nil
|
||||
|
44
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/event_test.go
generated
vendored
44
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/event_test.go
generated
vendored
@ -6,7 +6,10 @@ package docker
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@ -15,6 +18,39 @@ import (
|
||||
)
|
||||
|
||||
func TestEventListeners(t *testing.T) {
|
||||
testEventListeners("TestEventListeners", t, httptest.NewServer, NewClient)
|
||||
}
|
||||
|
||||
func TestTLSEventListeners(t *testing.T) {
|
||||
testEventListeners("TestTLSEventListeners", t, func(handler http.Handler) *httptest.Server {
|
||||
server := httptest.NewUnstartedServer(handler)
|
||||
|
||||
cert, err := tls.LoadX509KeyPair("testing/data/server.pem", "testing/data/serverkey.pem")
|
||||
if err != nil {
|
||||
t.Fatalf("Error loading server key pair: %s", err)
|
||||
}
|
||||
|
||||
caCert, err := ioutil.ReadFile("testing/data/ca.pem")
|
||||
if err != nil {
|
||||
t.Fatalf("Error loading ca certificate: %s", err)
|
||||
}
|
||||
caPool := x509.NewCertPool()
|
||||
if !caPool.AppendCertsFromPEM(caCert) {
|
||||
t.Fatalf("Could not add ca certificate")
|
||||
}
|
||||
|
||||
server.TLS = &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
RootCAs: caPool,
|
||||
}
|
||||
server.StartTLS()
|
||||
return server
|
||||
}, func(url string) (*Client, error) {
|
||||
return NewTLSClient(url, "testing/data/cert.pem", "testing/data/key.pem", "testing/data/ca.pem")
|
||||
})
|
||||
}
|
||||
|
||||
func testEventListeners(testName string, t *testing.T, buildServer func(http.Handler) *httptest.Server, buildClient func(string) (*Client, error)) {
|
||||
response := `{"status":"create","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
|
||||
{"status":"start","id":"dfdf82bd3881","from":"base:latest","time":1374067924}
|
||||
{"status":"stop","id":"dfdf82bd3881","from":"base:latest","time":1374067966}
|
||||
@ -22,7 +58,7 @@ func TestEventListeners(t *testing.T) {
|
||||
`
|
||||
|
||||
var req http.Request
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
server := buildServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rsc := bufio.NewScanner(strings.NewReader(response))
|
||||
for rsc.Scan() {
|
||||
w.Write([]byte(rsc.Text()))
|
||||
@ -33,7 +69,7 @@ func TestEventListeners(t *testing.T) {
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client, err := NewClient(server.URL)
|
||||
client, err := buildClient(server.URL)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create client: %s", err)
|
||||
}
|
||||
@ -53,7 +89,7 @@ func TestEventListeners(t *testing.T) {
|
||||
for {
|
||||
select {
|
||||
case msg := <-listener:
|
||||
t.Logf("Recieved: %s", *msg)
|
||||
t.Logf("Received: %s", *msg)
|
||||
count++
|
||||
err = checkEvent(count, msg)
|
||||
if err != nil {
|
||||
@ -63,7 +99,7 @@ func TestEventListeners(t *testing.T) {
|
||||
return
|
||||
}
|
||||
case <-timeout:
|
||||
t.Fatal("TestAddEventListener timed out waiting on events")
|
||||
t.Fatalf("%s timed out waiting on events", testName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/exec.go
generated
vendored
15
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/exec.go
generated
vendored
@ -50,8 +50,10 @@ type StartExecOptions struct {
|
||||
Success chan struct{} `json:"-"`
|
||||
}
|
||||
|
||||
// Exec is the type representing a `docker exec` instance and containing the
|
||||
// instance ID
|
||||
type Exec struct {
|
||||
Id string `json:"Id,omitempty" yaml:"Id,omitempty"`
|
||||
ID string `json:"Id,omitempty" yaml:"Id,omitempty"`
|
||||
}
|
||||
|
||||
// CreateExec sets up an exec instance in a running container `id`, returning the exec
|
||||
@ -76,9 +78,9 @@ func (c *Client) CreateExec(opts CreateExecOptions) (*Exec, error) {
|
||||
return &exec, nil
|
||||
}
|
||||
|
||||
// Starts a previously set up exec instance id. If opts.Detach is true, it returns
|
||||
// after starting the exec command. Otherwise, it sets up an interactive session
|
||||
// with the exec command.
|
||||
// StartExec starts a previously set up exec instance id. If opts.Detach is
|
||||
// true, it returns after starting the exec command. Otherwise, it sets up an
|
||||
// interactive session with the exec command.
|
||||
//
|
||||
// See http://goo.gl/JW8Lxl for more details
|
||||
func (c *Client) StartExec(id string, opts StartExecOptions) error {
|
||||
@ -102,8 +104,9 @@ func (c *Client) StartExec(id string, opts StartExecOptions) error {
|
||||
return c.hijack("POST", path, opts.Success, opts.RawTerminal, opts.InputStream, opts.ErrorStream, opts.OutputStream, opts)
|
||||
}
|
||||
|
||||
// Resizes the tty session used by the exec command id. This API is valid only
|
||||
// if Tty was specified as part of creating and starting the exec command.
|
||||
// ResizeExecTTY resizes the tty session used by the exec command id. This API
|
||||
// is valid only if Tty was specified as part of creating and starting the exec
|
||||
// command.
|
||||
//
|
||||
// See http://goo.gl/YDSx1f for more details
|
||||
func (c *Client) ResizeExecTTY(id string, height, width int) error {
|
||||
|
26
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/exec_test.go
generated
vendored
26
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/exec_test.go
generated
vendored
@ -16,7 +16,7 @@ import (
|
||||
|
||||
func TestExecCreate(t *testing.T) {
|
||||
jsonContainer := `{"Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"}`
|
||||
var expected struct{ Id string }
|
||||
var expected struct{ ID string }
|
||||
err := json.Unmarshal([]byte(jsonContainer), &expected)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -35,9 +35,9 @@ func TestExecCreate(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedId := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
if execObj.Id != expectedId {
|
||||
t.Errorf("ExecCreate: wrong ID. Want %q. Got %q.", expectedId, execObj.Id)
|
||||
expectedID := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
if execObj.ID != expectedID {
|
||||
t.Errorf("ExecCreate: wrong ID. Want %q. Got %q.", expectedID, execObj.ID)
|
||||
}
|
||||
req := fakeRT.requests[0]
|
||||
if req.Method != "POST" {
|
||||
@ -47,7 +47,7 @@ func TestExecCreate(t *testing.T) {
|
||||
if gotPath := req.URL.Path; gotPath != expectedURL.Path {
|
||||
t.Errorf("ExecCreate: Wrong path in request. Want %q. Got %q.", expectedURL.Path, gotPath)
|
||||
}
|
||||
var gotBody struct{ Id string }
|
||||
var gotBody struct{ ID string }
|
||||
err = json.NewDecoder(req.Body).Decode(&gotBody)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -55,13 +55,13 @@ func TestExecCreate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestExecStartDetached(t *testing.T) {
|
||||
execId := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
execID := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
fakeRT := &FakeRoundTripper{status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
config := StartExecOptions{
|
||||
Detach: true,
|
||||
}
|
||||
err := client.StartExec(execId, config)
|
||||
err := client.StartExec(execID, config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -69,7 +69,7 @@ func TestExecStartDetached(t *testing.T) {
|
||||
if req.Method != "POST" {
|
||||
t.Errorf("ExecStart: wrong HTTP method. Want %q. Got %q.", "POST", req.Method)
|
||||
}
|
||||
expectedURL, _ := url.Parse(client.getURL("/exec/" + execId + "/start"))
|
||||
expectedURL, _ := url.Parse(client.getURL("/exec/" + execID + "/start"))
|
||||
if gotPath := req.URL.Path; gotPath != expectedURL.Path {
|
||||
t.Errorf("ExecCreate: Wrong path in request. Want %q. Got %q.", expectedURL.Path, gotPath)
|
||||
}
|
||||
@ -97,7 +97,7 @@ func TestExecStartAndAttach(t *testing.T) {
|
||||
client.SkipServerVersionCheck = true
|
||||
var stdout, stderr bytes.Buffer
|
||||
success := make(chan struct{})
|
||||
execId := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
execID := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
opts := StartExecOptions{
|
||||
OutputStream: &stdout,
|
||||
ErrorStream: &stderr,
|
||||
@ -105,15 +105,15 @@ func TestExecStartAndAttach(t *testing.T) {
|
||||
RawTerminal: true,
|
||||
Success: success,
|
||||
}
|
||||
go client.StartExec(execId, opts)
|
||||
go client.StartExec(execID, opts)
|
||||
<-success
|
||||
}
|
||||
|
||||
func TestExecResize(t *testing.T) {
|
||||
execId := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
execID := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
|
||||
fakeRT := &FakeRoundTripper{status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
err := client.ResizeExecTTY(execId, 10, 20)
|
||||
err := client.ResizeExecTTY(execID, 10, 20)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -121,7 +121,7 @@ func TestExecResize(t *testing.T) {
|
||||
if req.Method != "POST" {
|
||||
t.Errorf("ExecStart: wrong HTTP method. Want %q. Got %q.", "POST", req.Method)
|
||||
}
|
||||
expectedURL, _ := url.Parse(client.getURL("/exec/" + execId + "/resize?h=10&w=20"))
|
||||
expectedURL, _ := url.Parse(client.getURL("/exec/" + execID + "/resize?h=10&w=20"))
|
||||
if gotPath := req.URL.RequestURI(); gotPath != expectedURL.RequestURI() {
|
||||
t.Errorf("ExecCreate: Wrong path in request. Want %q. Got %q.", expectedURL.Path, gotPath)
|
||||
}
|
||||
|
113
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/image.go
generated
vendored
113
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/image.go
generated
vendored
@ -25,9 +25,10 @@ type APIImages struct {
|
||||
Created int64 `json:"Created,omitempty" yaml:"Created,omitempty"`
|
||||
Size int64 `json:"Size,omitempty" yaml:"Size,omitempty"`
|
||||
VirtualSize int64 `json:"VirtualSize,omitempty" yaml:"VirtualSize,omitempty"`
|
||||
ParentId string `json:"ParentId,omitempty" yaml:"ParentId,omitempty"`
|
||||
ParentID string `json:"ParentId,omitempty" yaml:"ParentId,omitempty"`
|
||||
}
|
||||
|
||||
// Image is the type representing a docker image and its various properties
|
||||
type Image struct {
|
||||
ID string `json:"Id" yaml:"Id"`
|
||||
Parent string `json:"Parent,omitempty" yaml:"Parent,omitempty"`
|
||||
@ -52,6 +53,8 @@ type ImageHistory struct {
|
||||
Size int64 `json:"Size,omitempty" yaml:"Size,omitempty"`
|
||||
}
|
||||
|
||||
// ImagePre012 serves the same purpose as the Image type except that it is for
|
||||
// earlier versions of the Docker API (pre-012 to be specific)
|
||||
type ImagePre012 struct {
|
||||
ID string `json:"id"`
|
||||
Parent string `json:"parent,omitempty"`
|
||||
@ -66,6 +69,14 @@ type ImagePre012 struct {
|
||||
Size int64 `json:"size,omitempty"`
|
||||
}
|
||||
|
||||
// ListImagesOptions specify parameters to the ListImages function.
|
||||
//
|
||||
// See http://goo.gl/2rOLFF for more details.
|
||||
type ListImagesOptions struct {
|
||||
All bool
|
||||
Filters map[string][]string
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrNoSuchImage is the error returned when the image does not exist.
|
||||
ErrNoSuchImage = errors.New("no such image")
|
||||
@ -77,18 +88,17 @@ var (
|
||||
// ErrMissingOutputStream is the error returned when no output stream
|
||||
// is provided to some calls, like BuildImage.
|
||||
ErrMissingOutputStream = errors.New("missing output stream")
|
||||
|
||||
// ErrMultipleContexts is the error returned when both a ContextDir and
|
||||
// InputStream are provided in BuildImageOptions
|
||||
ErrMultipleContexts = errors.New("image build may not be provided BOTH context dir and input stream")
|
||||
)
|
||||
|
||||
// ListImages returns the list of available images in the server.
|
||||
//
|
||||
// See http://goo.gl/VmcR6v for more details.
|
||||
func (c *Client) ListImages(all bool) ([]APIImages, error) {
|
||||
path := "/images/json?all="
|
||||
if all {
|
||||
path += "1"
|
||||
} else {
|
||||
path += "0"
|
||||
}
|
||||
// See http://goo.gl/2rOLFF for more details.
|
||||
func (c *Client) ListImages(opts ListImagesOptions) ([]APIImages, error) {
|
||||
path := "/images/json?" + queryString(opts)
|
||||
body, _, err := c.do("GET", path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -146,7 +156,7 @@ func (c *Client) InspectImage(name string) (*Image, error) {
|
||||
var image Image
|
||||
|
||||
// if the caller elected to skip checking the server's version, assume it's the latest
|
||||
if c.SkipServerVersionCheck || c.expectedApiVersion.GreaterThanOrEqualTo(apiVersion_1_12) {
|
||||
if c.SkipServerVersionCheck || c.expectedAPIVersion.GreaterThanOrEqualTo(apiVersion1_12) {
|
||||
err = json.Unmarshal(body, &image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -194,9 +204,16 @@ type PushImageOptions struct {
|
||||
// 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"`
|
||||
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.
|
||||
@ -212,12 +229,7 @@ func (c *Client) PushImage(opts PushImageOptions, auth AuthConfiguration) error
|
||||
name := opts.Name
|
||||
opts.Name = ""
|
||||
path := "/images/" + name + "/push?" + queryString(&opts)
|
||||
var headers = make(map[string]string)
|
||||
var buf bytes.Buffer
|
||||
json.NewEncoder(&buf).Encode(auth)
|
||||
|
||||
headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes())
|
||||
|
||||
headers := headersWithAuth(auth)
|
||||
return c.stream("POST", path, true, opts.RawJSONStream, headers, nil, opts.OutputStream, nil)
|
||||
}
|
||||
|
||||
@ -241,11 +253,7 @@ func (c *Client) PullImage(opts PullImageOptions, auth AuthConfiguration) error
|
||||
return ErrNoSuchImage
|
||||
}
|
||||
|
||||
var headers = make(map[string]string)
|
||||
var buf bytes.Buffer
|
||||
json.NewEncoder(&buf).Encode(auth)
|
||||
headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes())
|
||||
|
||||
headers := headersWithAuth(auth)
|
||||
return c.createImage(queryString(&opts), headers, nil, opts.OutputStream, opts.RawJSONStream)
|
||||
}
|
||||
|
||||
@ -324,15 +332,18 @@ func (c *Client) ImportImage(opts ImportImageOptions) error {
|
||||
// For more details about the Docker building process, see
|
||||
// http://goo.gl/tlPXPu.
|
||||
type BuildImageOptions struct {
|
||||
Name string `qs:"t"`
|
||||
NoCache bool `qs:"nocache"`
|
||||
SuppressOutput bool `qs:"q"`
|
||||
RmTmpContainer bool `qs:"rm"`
|
||||
ForceRmTmpContainer bool `qs:"forcerm"`
|
||||
InputStream io.Reader `qs:"-"`
|
||||
OutputStream io.Writer `qs:"-"`
|
||||
RawJSONStream bool `qs:"-"`
|
||||
Remote string `qs:"remote"`
|
||||
Name string `qs:"t"`
|
||||
NoCache bool `qs:"nocache"`
|
||||
SuppressOutput bool `qs:"q"`
|
||||
RmTmpContainer bool `qs:"rm"`
|
||||
ForceRmTmpContainer bool `qs:"forcerm"`
|
||||
InputStream io.Reader `qs:"-"`
|
||||
OutputStream io.Writer `qs:"-"`
|
||||
RawJSONStream bool `qs:"-"`
|
||||
Remote string `qs:"remote"`
|
||||
Auth AuthConfiguration `qs:"-"` // for older docker X-Registry-Auth header
|
||||
AuthConfigs AuthConfigurations `qs:"-"` // for newer docker X-Registry-Config header
|
||||
ContextDir string `qs:"-"`
|
||||
}
|
||||
|
||||
// BuildImage builds an image from a tarball's url or a Dockerfile in the input
|
||||
@ -343,15 +354,26 @@ func (c *Client) BuildImage(opts BuildImageOptions) error {
|
||||
if opts.OutputStream == nil {
|
||||
return ErrMissingOutputStream
|
||||
}
|
||||
var headers map[string]string
|
||||
var headers = headersWithAuth(opts.Auth, opts.AuthConfigs)
|
||||
|
||||
if opts.Remote != "" && opts.Name == "" {
|
||||
opts.Name = opts.Remote
|
||||
}
|
||||
if opts.InputStream != nil {
|
||||
headers = map[string]string{"Content-Type": "application/tar"}
|
||||
if opts.InputStream != nil || opts.ContextDir != "" {
|
||||
headers["Content-Type"] = "application/tar"
|
||||
} else if opts.Remote == "" {
|
||||
return ErrMissingRepo
|
||||
}
|
||||
if opts.ContextDir != "" {
|
||||
if opts.InputStream != nil {
|
||||
return ErrMultipleContexts
|
||||
}
|
||||
var err error
|
||||
if opts.InputStream, err = createTarStream(opts.ContextDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return c.stream("POST", fmt.Sprintf("/build?%s",
|
||||
queryString(&opts)), true, opts.RawJSONStream, headers, opts.InputStream, opts.OutputStream, nil)
|
||||
}
|
||||
@ -389,6 +411,25 @@ func isURL(u string) bool {
|
||||
return p.Scheme == "http" || p.Scheme == "https"
|
||||
}
|
||||
|
||||
func headersWithAuth(auths ...interface{}) map[string]string {
|
||||
var headers = make(map[string]string)
|
||||
|
||||
for _, auth := range auths {
|
||||
switch auth.(type) {
|
||||
case AuthConfiguration:
|
||||
var buf bytes.Buffer
|
||||
json.NewEncoder(&buf).Encode(auth)
|
||||
headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes())
|
||||
case AuthConfigurations:
|
||||
var buf bytes.Buffer
|
||||
json.NewEncoder(&buf).Encode(auth)
|
||||
headers["X-Registry-Config"] = base64.URLEncoding.EncodeToString(buf.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
// APIImageSearch reflect the result of a search on the dockerHub
|
||||
//
|
||||
// See http://goo.gl/xI5lLZ for more details.
|
||||
|
31
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/image_test.go
generated
vendored
31
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/image_test.go
generated
vendored
@ -88,7 +88,7 @@ func TestListImages(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
client := newTestClient(&FakeRoundTripper{message: body, status: http.StatusOK})
|
||||
images, err := client.ListImages(false)
|
||||
images, err := client.ListImages(ListImagesOptions{})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -100,25 +100,42 @@ func TestListImages(t *testing.T) {
|
||||
func TestListImagesParameters(t *testing.T) {
|
||||
fakeRT := &FakeRoundTripper{message: "null", status: http.StatusOK}
|
||||
client := newTestClient(fakeRT)
|
||||
_, err := client.ListImages(false)
|
||||
_, err := client.ListImages(ListImagesOptions{All: false})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req := fakeRT.requests[0]
|
||||
if req.Method != "GET" {
|
||||
t.Errorf("ListImages(false: Wrong HTTP method. Want GET. Got %s.", req.Method)
|
||||
t.Errorf("ListImages({All: false}: Wrong HTTP method. Want GET. Got %s.", req.Method)
|
||||
}
|
||||
if all := req.URL.Query().Get("all"); all != "0" {
|
||||
t.Errorf("ListImages(false): Wrong parameter. Want all=0. Got all=%s", all)
|
||||
if all := req.URL.Query().Get("all"); all != "0" && all != "" {
|
||||
t.Errorf("ListImages({All: false}): Wrong parameter. Want all=0 or not present at all. Got all=%s", all)
|
||||
}
|
||||
fakeRT.Reset()
|
||||
_, err = client.ListImages(true)
|
||||
_, err = client.ListImages(ListImagesOptions{All: true})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req = fakeRT.requests[0]
|
||||
if all := req.URL.Query().Get("all"); all != "1" {
|
||||
t.Errorf("ListImages(true): Wrong parameter. Want all=1. Got all=%s", all)
|
||||
t.Errorf("ListImages({All: true}): Wrong parameter. Want all=1. Got all=%s", all)
|
||||
}
|
||||
fakeRT.Reset()
|
||||
_, err = client.ListImages(ListImagesOptions{Filters: map[string][]string{
|
||||
"dangling": {"true"},
|
||||
}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req = fakeRT.requests[0]
|
||||
body := req.URL.Query().Get("filters")
|
||||
var filters map[string][]string
|
||||
err = json.Unmarshal([]byte(body), &filters)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(filters["dangling"]) != 1 || filters["dangling"][0] != "true" {
|
||||
t.Errorf("ListImages(dangling=[true]): Wrong filter map. Want dangling=[true], got dangling=%v", filters["dangling"])
|
||||
}
|
||||
}
|
||||
|
||||
|
99
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/tar.go
generated
vendored
Normal file
99
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/tar.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
// 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 LICENSE file.
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
)
|
||||
|
||||
func createTarStream(srcPath string) (io.ReadCloser, error) {
|
||||
excludes, err := parseDockerignore(srcPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := validateContextDirectory(srcPath, excludes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tarOpts := &archive.TarOptions{
|
||||
Excludes: excludes,
|
||||
Compression: archive.Uncompressed,
|
||||
NoLchown: true,
|
||||
}
|
||||
return archive.TarWithOptions(srcPath, tarOpts)
|
||||
}
|
||||
|
||||
// validateContextDirectory checks if all the contents of the directory
|
||||
// can be read and returns an error if some files can't be read.
|
||||
// Symlinks which point to non-existing files don't trigger an error
|
||||
func validateContextDirectory(srcPath string, excludes []string) error {
|
||||
return filepath.Walk(filepath.Join(srcPath, "."), func(filePath string, f os.FileInfo, err error) error {
|
||||
// skip this directory/file if it's not in the path, it won't get added to the context
|
||||
if relFilePath, err := filepath.Rel(srcPath, filePath); err != nil {
|
||||
return err
|
||||
} else if skip, err := fileutils.Matches(relFilePath, excludes); err != nil {
|
||||
return err
|
||||
} else if skip {
|
||||
if f.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if os.IsPermission(err) {
|
||||
return fmt.Errorf("can't stat '%s'", filePath)
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// skip checking if symlinks point to non-existing files, such symlinks can be useful
|
||||
// also skip named pipes, because they hanging on open
|
||||
if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !f.IsDir() {
|
||||
currentFile, err := os.Open(filePath)
|
||||
if err != nil && os.IsPermission(err) {
|
||||
return fmt.Errorf("no permission to read from '%s'", filePath)
|
||||
}
|
||||
currentFile.Close()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func parseDockerignore(root string) ([]string, error) {
|
||||
var excludes []string
|
||||
ignore, err := ioutil.ReadFile(path.Join(root, ".dockerignore"))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return excludes, fmt.Errorf("error reading .dockerignore: '%s'", err)
|
||||
}
|
||||
for _, pattern := range strings.Split(string(ignore), "\n") {
|
||||
matches, err := filepath.Match(pattern, "Dockerfile")
|
||||
if err != nil {
|
||||
return excludes, fmt.Errorf("bad .dockerignore pattern: '%s', error: %s", pattern, err)
|
||||
}
|
||||
if matches {
|
||||
return excludes, fmt.Errorf("dockerfile was excluded by .dockerignore pattern '%s'", pattern)
|
||||
}
|
||||
excludes = append(excludes, pattern)
|
||||
}
|
||||
|
||||
return excludes, nil
|
||||
}
|
38
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/bin/fmtpolice
generated
vendored
Normal file
38
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/bin/fmtpolice
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
readonly GOPATH="${GOPATH%%:*}"
|
||||
|
||||
main() {
|
||||
check_fmt
|
||||
check_lint
|
||||
}
|
||||
|
||||
check_fmt() {
|
||||
eval "set -e"
|
||||
for file in $(git ls-files '*.go') ; do
|
||||
gofmt $file | diff -u $file -
|
||||
done
|
||||
eval "set +e"
|
||||
}
|
||||
|
||||
check_lint() {
|
||||
_install_linter
|
||||
|
||||
for file in $(git ls-files '*.go') ; do
|
||||
if [[ ! "$(${GOPATH}/bin/golint $file)" =~ ^[[:blank:]]*$ ]] ; then
|
||||
_lint_verbose && exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
_lint_verbose() {
|
||||
for file in $(git ls-files '*.go') ; do $GOPATH/bin/golint $file ; done
|
||||
}
|
||||
|
||||
_install_linter() {
|
||||
if [[ ! -x "${GOPATH}/bin/golint" ]] ; then
|
||||
go get -u github.com/golang/lint/golint
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
3
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/.dockerignore
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/.dockerignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
container.tar
|
||||
dockerfile.tar
|
||||
foofile
|
0
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/barfile
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/barfile
generated
vendored
Normal file
18
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/ca.pem
generated
vendored
Normal file
18
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/ca.pem
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC1TCCAb+gAwIBAgIQJ9MsNxrUxumNbAytGi3GEDALBgkqhkiG9w0BAQswFjEU
|
||||
MBIGA1UEChMLQm9vdDJEb2NrZXIwHhcNMTQxMDE2MjAyMTM4WhcNMTcwOTMwMjAy
|
||||
MTM4WjAWMRQwEgYDVQQKEwtCb290MkRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBALpFCSARjG+5yXoqr7UMzuE0df7RRZfeRZI06lJ02ZqV4Iii
|
||||
rgL7ML9yPxX50NbLnjiilSDTUhnyocYFItokzUzz8qpX/nlYhuN2Iqwh4d0aWS8z
|
||||
f5y248F+H1z+HY2W8NPl/6DVlVwYaNW1/k+RPMlHS0INLR6j+3Ievew7RNE0NnM2
|
||||
znELW6NetekDt3GUcz0Z95vDUDfdPnIk1eIFMmYvLxZh23xOca4Q37a3S8F3d+dN
|
||||
+OOpwjdgY9Qme0NQUaXpgp58jWuQfB8q7mZrdnLlLqRa8gx1HeDSotX7UmWtWPkb
|
||||
vd9EdlKLYw5PVpxMV1rkwf2t4TdgD5NfkpXlXkkCAwEAAaMjMCEwDgYDVR0PAQH/
|
||||
BAQDAgCkMA8GA1UdEwEB/wQFMAMBAf8wCwYJKoZIhvcNAQELA4IBAQBxYjHVSKqE
|
||||
MJw7CW0GddesULtXXVWGJuZdWJLQlPvPMfIfjIvlcZyS4cdVNiQ3sREFIZz8TpII
|
||||
CT0/Pg3sgv/FcOQe1CN0xZYZcyiAZHK1z0fJQq2qVpdv7+tJcjI2vvU6NI24iQCo
|
||||
W1wz25trJz9QbdB2MRLMjyz7TSWuafztIvcfEzaIdQ0Whqund/cSuPGQx5IwF83F
|
||||
rvlkOyJSH2+VIEBTCIuykJeL0DLTt8cePBQR5L1ISXb4RUMK9ZtqRscBRv8sn7o2
|
||||
ixG3wtL0gYF4xLtsQWVxI3iFVrU3WzOH/3c5shVRkWBd+AQRSwCJI4mKH7penJCF
|
||||
i3/zzlkvOnjV
|
||||
-----END CERTIFICATE-----
|
18
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/cert.pem
generated
vendored
Normal file
18
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/cert.pem
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC6DCCAdKgAwIBAgIRANO6ymxQAjp66KmEka1G6b0wCwYJKoZIhvcNAQELMBYx
|
||||
FDASBgNVBAoTC0Jvb3QyRG9ja2VyMB4XDTE0MTAxNjIwMjE1MloXDTE3MDkzMDIw
|
||||
MjE1MlowFjEUMBIGA1UEChMLQm9vdDJEb2NrZXIwggEiMA0GCSqGSIb3DQEBAQUA
|
||||
A4IBDwAwggEKAoIBAQDGA1mAhSOpZspD1dpZ7qVEQrIJw4Xo8252jHaORnEdDiFm
|
||||
b6brEmr6jw8t4P3IGxbqBc/TqRV+SSXxwYEVvfpeQKH+SmqStoMNtD3Ura161az4
|
||||
V0BcxMtSlsUGpoz+//QCAq8qiaxMwgiyc5253mkQm88anj2cNt7xbewiu/KFWuf7
|
||||
BVpNK1+ltpJmlukfcj/G+I1bw7j1KxBjDrFqe5cyDuuZcDL2tmUXP/ZWDyXwSv+H
|
||||
AOckqn44z6aXlBkVvOXDBZJqY76d/vWVDNCuZeXRnqlhP3t1kH4V0RQXo+JD2tgt
|
||||
JgdU0unzyoFOSWNUBPm73tqmjUGGAmGHBmeegJr/AgMBAAGjNTAzMA4GA1UdDwEB
|
||||
/wQEAwIAgDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMAsGCSqG
|
||||
SIb3DQEBCwOCAQEABVTWl5SmBP+j5He5bQsgnIXjviSKqe40/10V4LJAOmilycRF
|
||||
zLrzM+YMwfjg6PLIs8CldAMWHw9y9ktZY4MxkgCktaiaN/QmMTMwFWEcN4wy5IpM
|
||||
U5l93eAg7xsnY430h3QBBADujX4wdF3fs8rSL8zAAQFL0ihurwU124K3yXKsrwpb
|
||||
CiVUGfIN4sPwjy8Ws9oxHFDC9/P8lgjHZ1nBIf8KSHnMzlxDGj7isQfhtH+7mcCL
|
||||
cM1qO2NirS2v7uaEPPY+MJstAz+W7EJCW9dfMSmHna2SDC37Xkin7uEY9z+qaKFL
|
||||
8d/XxOB/L8Ucy8VZhdsv0dsBq5KfJntITM0ksQ==
|
||||
-----END CERTIFICATE-----
|
0
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/foofile
generated
vendored
Normal file
0
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/foofile
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/key.pem
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/key.pem
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAxgNZgIUjqWbKQ9XaWe6lREKyCcOF6PNudox2jkZxHQ4hZm+m
|
||||
6xJq+o8PLeD9yBsW6gXP06kVfkkl8cGBFb36XkCh/kpqkraDDbQ91K2tetWs+FdA
|
||||
XMTLUpbFBqaM/v/0AgKvKomsTMIIsnOdud5pEJvPGp49nDbe8W3sIrvyhVrn+wVa
|
||||
TStfpbaSZpbpH3I/xviNW8O49SsQYw6xanuXMg7rmXAy9rZlFz/2Vg8l8Er/hwDn
|
||||
JKp+OM+ml5QZFbzlwwWSamO+nf71lQzQrmXl0Z6pYT97dZB+FdEUF6PiQ9rYLSYH
|
||||
VNLp88qBTkljVAT5u97apo1BhgJhhwZnnoCa/wIDAQABAoIBAQCaGy9EC9pmU95l
|
||||
DwGh7k5nIrUnTilg1FwLHWSDdCVCZKXv8ENrPelOWZqJrUo1u4eI2L8XTsewgkNq
|
||||
tJu/DRzWz9yDaO0qg6rZNobMh+K076lvmZA44twOydJLS8H+D7ua+PXU2FLlZjmY
|
||||
kMyXRJZmW6zCXZc7haTbJx6ZJccoquk/DkS4FcFurJP177u1YrWS9TTw9kensUtU
|
||||
jQ63uf56UTN1i+0+Rxl7OW1TZlqwlri5I4njg5249+FxwwHzIq8+l7zD7K9pl8c/
|
||||
nG1HuulvU2bVlDlRdyslMPAH34vw9Sku1BD8furrJLr1na5lRSLKJODEaIPEsLwv
|
||||
CdEUwP9JAoGBAO76ZW80RyNB2fA+wbTq70Sr8CwrXxYemXrez5LKDC7SsohKFCPE
|
||||
IedpO/n+nmymiiJvMm874EExoG6BVrbkWkeb+2vinEfOQNlDMsDx7WLjPekP3t6i
|
||||
rXHO3CjFooVFq2z3mZa/Nc5NZqu8fNWNCKJxZDJphdoj6sORNJIUvZVjAoGBANQd
|
||||
++J+ITcu3/+A6JrGcgLunBFQYPqkiItk0J4QKYKuX5ik9rWcQDN8TTtfW2mDuiQ4
|
||||
NrCwuVPq1V1kB16JzH017SsYLo9g8I20YjnBZge9pKTeUaLVTb3C50LW8FBylop0
|
||||
Bnm597dNbtSjphjoTMg0XyC19o3Esf2YeWG0QNS1AoGAWWDfFRNJU99qIldmXULM
|
||||
0DM6NVrXSk+ReYnhunXEzrJQwXZrR+EwCPurydk36Uz0NuK9yypquhdUeF/5TZfk
|
||||
SAoHo5byekyipl9imRUigqyY2BTudvgCxKDoaHtaSFwBPFTyZZYICquaLbrmOXxw
|
||||
8UhVgCFFRYvPXuts7QHC0h8CgYBWEvy9gfU0kV7wLX02IUTuj6jhFb7ktpN6DSTi
|
||||
nyhZES1VoctDEu6ydcRZTW6ouH12aSE4Pd5WgTqntQmQgVZrkNB25k8ue2Xh+srJ
|
||||
KQOgLIJ9LIHwE6KCWG7DnrjRzE3uTPq7to0g4tkQjH/AJ7PQof/gJDayfJjFkXPg
|
||||
A+cy6QKBgEPbKpiqscm03gT2QanBut5pg4dqPOxp0SlErA3kSFNTRK3oYBQPC+LH
|
||||
qA5nD5brdkeNBB58Rll8Zpzxiff50bcvLP/7/Sb3NjaXFTEY0gVbdRof3n6N0YP3
|
||||
Hu5XDNJ9RNkNzE5RIG1g86KE+aKlcrKMaigqAiuIy2PSnjkQeGk8
|
||||
-----END RSA PRIVATE KEY-----
|
18
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/server.pem
generated
vendored
Normal file
18
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/server.pem
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC/DCCAeagAwIBAgIQMUILcXtvmSOK63zEBo0VXzALBgkqhkiG9w0BAQswFjEU
|
||||
MBIGA1UEChMLQm9vdDJEb2NrZXIwHhcNMTQxMDE2MjAyMTQ2WhcNMTcwOTMwMjAy
|
||||
MTQ2WjAWMRQwEgYDVQQKEwtCb290MkRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBANxUOUhNnqFnrTlLsBYzfFRZWQo268l+4K4lOJCVbfDonP3g
|
||||
Mz0vGi9fcyFqEWSA8Y+ShXna625HTnReCwFdsu0861qCIq7v95hFFCyOe0iIxpd0
|
||||
AKLnl90d+1vonE7andgFgoobbTiMly4UK4H6z8D148fFNIihoteOG3PIF89TFxP7
|
||||
CJ/3wXnx/IKpdlO8PAnub3tBPJHvGDj7KORLy4IBxRX5VBAdfGNybE66fcrehEva
|
||||
rLA4m9pgiaR/Nnr9FdKhPyqYdjflLNvzydxNvMIV4M0hFlhXmYvpMjA5/XsTnsyV
|
||||
t9JHJa5Upwqsbne08t7rsm7liZNxZlko8xPOTQcCAwEAAaNKMEgwDgYDVR0PAQH/
|
||||
BAQDAgCgMAwGA1UdEwEB/wQCMAAwKAYDVR0RBCEwH4ILYm9vdDJkb2NrZXKHBH8A
|
||||
AAGHBAoAAg+HBMCoO2cwCwYJKoZIhvcNAQELA4IBAQAYoYcDkDWkl73FZ0WnPmAj
|
||||
LiF7HU95Qg3KyEpFsAJeShSLPPbQntmwhdekEzY4tQ3eKQB/+zHFjzsCr/lmDUmH
|
||||
Ea/ryQ17C+jyH+Ykg0IWW6L6veZhvRDg6Z9focVtPVBRxPTqC/Qhb54blWRASV+W
|
||||
UreMuXQ5+1dQptAM7ixOeLVHjBi/bd9TL3jvwBVCr9QedteMjjK4TCF9Tbcou+MF
|
||||
2w3OJJZMDhcD+YwoK9uJDqlKmcTm/vVMbSsp/pTMcnQ7jxCeR8/XyX+VwTZwaHAa
|
||||
o92Q/eg3THAiWhvyT/SzyH9dHHBAyXynUwGCggKawHktfvW4QXRPuLxLrJ7iB5cy
|
||||
-----END CERTIFICATE-----
|
27
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/serverkey.pem
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/serverkey.pem
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEoAIBAAKCAQEA3FQ5SE2eoWetOUuwFjN8VFlZCjbryX7griU4kJVt8Oic/eAz
|
||||
PS8aL19zIWoRZIDxj5KFedrrbkdOdF4LAV2y7TzrWoIiru/3mEUULI57SIjGl3QA
|
||||
oueX3R37W+icTtqd2AWCihttOIyXLhQrgfrPwPXjx8U0iKGi144bc8gXz1MXE/sI
|
||||
n/fBefH8gql2U7w8Ce5ve0E8ke8YOPso5EvLggHFFflUEB18Y3JsTrp9yt6ES9qs
|
||||
sDib2mCJpH82ev0V0qE/Kph2N+Us2/PJ3E28whXgzSEWWFeZi+kyMDn9exOezJW3
|
||||
0kclrlSnCqxud7Ty3uuybuWJk3FmWSjzE85NBwIDAQABAoIBAG0ak+cW8LeShHf7
|
||||
3+2Of0GxoOLrAWWdG5uAuPr31CJYve0FybnBimDtDjD8ujIfm/7xmoEWBEFutA3x
|
||||
x9dcU88gvJbsHEqub9gKVQwfXjMz78tt2SbSMiR/xUnk7QorPcCMMfE71aEMFYzu
|
||||
1gCed6Rg3vO81t/V0rKVH0j9S7UQz5v/oX15eVDV5LOqyCHwAi6K0eXXbqnbI0TH
|
||||
SOQ/nexM2msVXWbO9t6ra6f5V7FXziDK5Xi+rPxRbX9mkrDzxDAevfuRqYBx5vtL
|
||||
W2Q2hKjUAHFgXFniNSZBS7dCdAtz0el/3ct+cNmpuTMhhs7M6wC1CuYiZ/DxLiFh
|
||||
Si73VckCgYEA+/ceh3+VjtQ0rgEw8sD9bqYEA8IaBiObjneIoFnKBYRG7yZd8JMm
|
||||
HD4M/aQ1qhcRLPN7GR03YQULgQJURbKSjJHnhfTXHyeHC3NN4gMVHQXewu2MHCh6
|
||||
7FCQ9CfK0KcYLgegVVvL3PrF3hyWGnmTu+G0UkDQRYVnaNrB7snrW6UCgYEA39tq
|
||||
+MCQdu0moJ5szSZf02undg9EeW6isk9qzi7TId3/MLci2eH7PEnipipPUK3+DERq
|
||||
aba0y0TKgBR2EXvXLFJA/+kfdo2loIEHOfox85HVfxgUaFRti63ZI0uF8D0QT2Yy
|
||||
oJal+RFghVoSnv4LjhRKEPbIkScTXGjdK+7wFjsCfz79iKRXQQx0ALd/lL0bgkAn
|
||||
QNmvrNHcFQeI2p8700WNzC39aX67SsvEt3qxkrjzC1gxhpTAuReIK1gVPPwvqHN8
|
||||
BmV20FD5kMlMCix2mNCopwgUWvKvLAvoGFTxncKMA39+aJbuXAjiqJTekKgNvOE7
|
||||
i9kEWw0GTNPp3JHV6QECgYAPwb0M11kT1euDIMOdyRazpf86kyaJuZzgGjD1ZFxe
|
||||
JOcigbGFTp/FhZnbglzk2+pm6KXo3QBq0mPCki4hWusxZnTGzpz1VlETNCHTFeZQ
|
||||
M7KoaIR/N3oie9Et59H8r/+m5xWnMhNqratyl316DX24uXrhKM3DUdHODl+LCR2D
|
||||
IwKBgE1MbHuwolUPEw3HeO4R7NMFVTFei7E/fpUsimPfArGg8UydwvloNT1myJos
|
||||
N2JzfGGjN2KPVcBk9fOs71mJ6VcK3C3g5JIccplk6h9VNaw55+zdQvKPTzoBoTvy
|
||||
A+Fwx2AlF61KeRF87DL2YTRJ6B9MHmWgf7+GVZOxomLgEAcZ
|
||||
-----END RSA PRIVATE KEY-----
|
1
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/symlink
generated
vendored
Symbolic link
1
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/data/symlink
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
doesnotexist
|
70
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/server.go
generated
vendored
70
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/server.go
generated
vendored
@ -34,6 +34,7 @@ import (
|
||||
// For more details on the remote API, check http://goo.gl/G3plxW.
|
||||
type DockerServer struct {
|
||||
containers []*docker.Container
|
||||
execs []*docker.Exec
|
||||
cMut sync.RWMutex
|
||||
images []docker.Image
|
||||
iMut sync.RWMutex
|
||||
@ -90,18 +91,22 @@ func (s *DockerServer) buildMuxer() {
|
||||
s.mux.Path("/containers/{id:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectContainer))
|
||||
s.mux.Path("/containers/{id:.*}/top").Methods("GET").HandlerFunc(s.handlerWrapper(s.topContainer))
|
||||
s.mux.Path("/containers/{id:.*}/start").Methods("POST").HandlerFunc(s.handlerWrapper(s.startContainer))
|
||||
s.mux.Path("/containers/{id:.*}/kill").Methods("POST").HandlerFunc(s.handlerWrapper(s.stopContainer))
|
||||
s.mux.Path("/containers/{id:.*}/stop").Methods("POST").HandlerFunc(s.handlerWrapper(s.stopContainer))
|
||||
s.mux.Path("/containers/{id:.*}/pause").Methods("POST").HandlerFunc(s.handlerWrapper(s.pauseContainer))
|
||||
s.mux.Path("/containers/{id:.*}/unpause").Methods("POST").HandlerFunc(s.handlerWrapper(s.unpauseContainer))
|
||||
s.mux.Path("/containers/{id:.*}/wait").Methods("POST").HandlerFunc(s.handlerWrapper(s.waitContainer))
|
||||
s.mux.Path("/containers/{id:.*}/attach").Methods("POST").HandlerFunc(s.handlerWrapper(s.attachContainer))
|
||||
s.mux.Path("/containers/{id:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeContainer))
|
||||
s.mux.Path("/containers/{id:.*}/exec").Methods("POST").HandlerFunc(s.handlerWrapper(s.createExecContainer))
|
||||
s.mux.Path("/exec/{id:.*}/start").Methods("POST").HandlerFunc(s.handlerWrapper(s.startExecContainer))
|
||||
s.mux.Path("/images/create").Methods("POST").HandlerFunc(s.handlerWrapper(s.pullImage))
|
||||
s.mux.Path("/build").Methods("POST").HandlerFunc(s.handlerWrapper(s.buildImage))
|
||||
s.mux.Path("/images/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.listImages))
|
||||
s.mux.Path("/images/{id:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeImage))
|
||||
s.mux.Path("/images/{name:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectImage))
|
||||
s.mux.Path("/images/{name:.*}/push").Methods("POST").HandlerFunc(s.handlerWrapper(s.pushImage))
|
||||
s.mux.Path("/images/{name:.*}/tag").Methods("POST").HandlerFunc(s.handlerWrapper(s.tagImage))
|
||||
s.mux.Path("/events").Methods("GET").HandlerFunc(s.listEvents)
|
||||
s.mux.Path("/_ping").Methods("GET").HandlerFunc(s.handlerWrapper(s.pingDocker))
|
||||
s.mux.Path("/images/load").Methods("POST").HandlerFunc(s.handlerWrapper(s.loadImage))
|
||||
@ -173,8 +178,8 @@ 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.
|
||||
// DefaultHandler returns default http.Handler mux, it allows customHandlers to
|
||||
// call the default behavior if wanted.
|
||||
func (s *DockerServer) DefaultHandler() http.Handler {
|
||||
return s.mux
|
||||
}
|
||||
@ -210,6 +215,7 @@ func (s *DockerServer) listContainers(w http.ResponseWriter, r *http.Request) {
|
||||
Created: container.Created.Unix(),
|
||||
Status: container.State.String(),
|
||||
Ports: container.NetworkSettings.PortMappingAPI(),
|
||||
Names: []string{fmt.Sprintf("/%s", container.Name)},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -269,8 +275,7 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
image, err := s.findImage(config.Image)
|
||||
if err != nil {
|
||||
if _, err := s.findImage(config.Image); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
@ -278,7 +283,7 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
|
||||
ports := map[docker.Port][]docker.PortBinding{}
|
||||
for port := range config.ExposedPorts {
|
||||
ports[port] = []docker.PortBinding{{
|
||||
HostIp: "0.0.0.0",
|
||||
HostIP: "0.0.0.0",
|
||||
HostPort: strconv.Itoa(mathrand.Int() % 65536),
|
||||
}}
|
||||
}
|
||||
@ -294,6 +299,7 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
container := docker.Container{
|
||||
Name: r.URL.Query().Get("name"),
|
||||
ID: s.generateID(),
|
||||
Created: time.Now(),
|
||||
Path: path,
|
||||
@ -305,7 +311,7 @@ func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
|
||||
ExitCode: 0,
|
||||
StartedAt: time.Now(),
|
||||
},
|
||||
Image: image,
|
||||
Image: config.Image,
|
||||
NetworkSettings: &docker.NetworkSettings{
|
||||
IPAddress: fmt.Sprintf("172.16.42.%d", mathrand.Int()%250+2),
|
||||
IPPrefixLen: 24,
|
||||
@ -557,8 +563,10 @@ func (s *DockerServer) buildImage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
//we did not use that Dockerfile to build image cause we are a fake Docker daemon
|
||||
image := docker.Image{
|
||||
ID: s.generateID(),
|
||||
ID: s.generateID(),
|
||||
Created: time.Now(),
|
||||
}
|
||||
|
||||
query := r.URL.Query()
|
||||
repository := image.ID
|
||||
if t := query.Get("t"); t != "" {
|
||||
@ -597,6 +605,22 @@ func (s *DockerServer) pushImage(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "Pushed")
|
||||
}
|
||||
|
||||
func (s *DockerServer) tagImage(w http.ResponseWriter, r *http.Request) {
|
||||
name := mux.Vars(r)["name"]
|
||||
s.iMut.RLock()
|
||||
if _, ok := s.imgIDs[name]; !ok {
|
||||
s.iMut.RUnlock()
|
||||
http.Error(w, "No such image", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
s.iMut.RUnlock()
|
||||
s.iMut.Lock()
|
||||
defer s.iMut.Unlock()
|
||||
newRepo := r.URL.Query().Get("repo")
|
||||
s.imgIDs[newRepo] = s.imgIDs[name]
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
|
||||
func (s *DockerServer) removeImage(w http.ResponseWriter, r *http.Request) {
|
||||
id := mux.Vars(r)["id"]
|
||||
s.iMut.RLock()
|
||||
@ -604,6 +628,12 @@ func (s *DockerServer) removeImage(w http.ResponseWriter, r *http.Request) {
|
||||
if img, ok := s.imgIDs[id]; ok {
|
||||
id, tag = img, id
|
||||
}
|
||||
var tags []string
|
||||
for tag, taggedID := range s.imgIDs {
|
||||
if taggedID == id {
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
}
|
||||
s.iMut.RUnlock()
|
||||
_, index, err := s.findImageByID(id)
|
||||
if err != nil {
|
||||
@ -613,8 +643,10 @@ func (s *DockerServer) removeImage(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
s.iMut.Lock()
|
||||
defer s.iMut.Unlock()
|
||||
s.images[index] = s.images[len(s.images)-1]
|
||||
s.images = s.images[:len(s.images)-1]
|
||||
if len(tags) < 2 {
|
||||
s.images[index] = s.images[len(s.images)-1]
|
||||
s.images = s.images[:len(s.images)-1]
|
||||
}
|
||||
if tag != "" {
|
||||
delete(s.imgIDs, tag)
|
||||
}
|
||||
@ -690,3 +722,23 @@ func (s *DockerServer) getImage(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/tar")
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerServer) createExecContainer(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
exec := docker.Exec{ID: "id-exec-created-by-test"}
|
||||
s.execs = append(s.execs, &exec)
|
||||
json.NewEncoder(w).Encode(map[string]string{"Id": exec.ID})
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerServer) startExecContainer(w http.ResponseWriter, r *http.Request) {
|
||||
id := mux.Vars(r)["id"]
|
||||
for _, exec := range s.execs {
|
||||
if exec.ID == id {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
|
74
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/server_test.go
generated
vendored
74
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/server_test.go
generated
vendored
@ -120,6 +120,7 @@ func TestListContainers(t *testing.T) {
|
||||
Created: container.Created.Unix(),
|
||||
Status: container.State.String(),
|
||||
Ports: container.NetworkSettings.PortMappingAPI(),
|
||||
Names: []string{"/" + container.Name},
|
||||
}
|
||||
}
|
||||
var got []docker.APIContainers
|
||||
@ -473,6 +474,23 @@ func TestStopContainer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestKillContainer(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addContainers(&server, 1)
|
||||
server.containers[0].State.Running = true
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/containers/%s/kill", server.containers[0].ID)
|
||||
request, _ := http.NewRequest("POST", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusNoContent {
|
||||
t.Errorf("KillContainer: wrong status code. Want %d. Got %d.", http.StatusNoContent, recorder.Code)
|
||||
}
|
||||
if server.containers[0].State.Running {
|
||||
t.Error("KillContainer: did not stop the container")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStopContainerWithNotifyChannel(t *testing.T) {
|
||||
ch := make(chan *docker.Container, 1)
|
||||
server := DockerServer{}
|
||||
@ -771,12 +789,38 @@ func TestPushImageNotFound(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagImage(t *testing.T) {
|
||||
server := DockerServer{imgIDs: map[string]string{"tsuru/python": "a123"}}
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("POST", "/images/tsuru/python/tag?repo=tsuru/new-python", nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusCreated {
|
||||
t.Errorf("TagImage: wrong status. Want %d. Got %d.", http.StatusCreated, recorder.Code)
|
||||
}
|
||||
if server.imgIDs["tsuru/python"] != server.imgIDs["tsuru/new-python"] {
|
||||
t.Errorf("TagImage: did not tag the image")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagImageNotFound(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
server.buildMuxer()
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest("POST", "/images/tsuru/python/tag", nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusNotFound {
|
||||
t.Errorf("TagImage: wrong status. Want %d. Got %d.", http.StatusNotFound, recorder.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func addContainers(server *DockerServer, n int) {
|
||||
server.cMut.Lock()
|
||||
defer server.cMut.Unlock()
|
||||
for i := 0; i < n; i++ {
|
||||
date := time.Now().Add(time.Duration((rand.Int() % (i + 1))) * time.Hour)
|
||||
container := docker.Container{
|
||||
Name: fmt.Sprintf("%x", rand.Int()%10000),
|
||||
ID: fmt.Sprintf("%x", rand.Int()%10000),
|
||||
Created: date,
|
||||
Path: "ls",
|
||||
@ -896,6 +940,36 @@ func TestRemoveImageByName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveImageWithMultipleTags(t *testing.T) {
|
||||
server := DockerServer{}
|
||||
addImages(&server, 1, true)
|
||||
server.buildMuxer()
|
||||
imgID := server.images[0].ID
|
||||
imgName := "docker/python-" + imgID
|
||||
server.imgIDs["docker/python-wat"] = imgID
|
||||
recorder := httptest.NewRecorder()
|
||||
path := fmt.Sprintf("/images/%s", imgName)
|
||||
request, _ := http.NewRequest("DELETE", path, nil)
|
||||
server.ServeHTTP(recorder, request)
|
||||
_, ok := server.imgIDs[imgName]
|
||||
if ok {
|
||||
t.Error("RemoveImage: did not remove image tag name.")
|
||||
}
|
||||
id, ok := server.imgIDs["docker/python-wat"]
|
||||
if !ok {
|
||||
t.Error("RemoveImage: removed the wrong tag name.")
|
||||
}
|
||||
if id != imgID {
|
||||
t.Error("RemoveImage: disassociated the wrong ID from the tag")
|
||||
}
|
||||
if len(server.images) < 1 {
|
||||
t.Fatal("RemoveImage: removed the image, but should keep it")
|
||||
}
|
||||
if server.images[0].ID != imgID {
|
||||
t.Error("RemoveImage: changed the ID of the image!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareFailure(t *testing.T) {
|
||||
server := DockerServer{failures: make(map[string]string)}
|
||||
server.buildMuxer()
|
||||
|
6
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/writer.go
generated
vendored
6
Godeps/_workspace/src/github.com/fsouza/go-dockerclient/testing/writer.go
generated
vendored
@ -13,9 +13,9 @@ import (
|
||||
type stdType [8]byte
|
||||
|
||||
var (
|
||||
stdin stdType = stdType{0: 0}
|
||||
stdout stdType = stdType{0: 1}
|
||||
stderr stdType = stdType{0: 2}
|
||||
stdin = stdType{0: 0}
|
||||
stdout = stdType{0: 1}
|
||||
stderr = stdType{0: 2}
|
||||
)
|
||||
|
||||
type stdWriter struct {
|
||||
|
Loading…
Reference in New Issue
Block a user