diff --git a/hack/vendor.sh b/hack/vendor.sh index dae1fa837e..0a7731b159 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -7,7 +7,7 @@ source 'hack/.vendor-helpers.sh' # the following lines are in sorted order, FYI clone git github.com/Azure/go-ansiterm 70b2c90b260171e829f1ebd7c17f600c11858dbe -clone git github.com/Microsoft/go-winio 2b085935f02c272e7a1855df6f8fe03029ffcadd +clone git github.com/Microsoft/go-winio eb176a9831c54b88eaf9eb4fbc24b94080d910ad clone git github.com/Sirupsen/logrus v0.9.0 # logrus is a common dependency among multiple deps clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a clone git github.com/go-check/check 11d3bc7aa68e238947792f30573146a3231fc0f1 @@ -23,8 +23,8 @@ clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://github.com/golang/net.git clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3 -clone git github.com/docker/go-connections v0.1.2 -clone git github.com/docker/engine-api bdbab71ec21209ef56dffdbe42c9d21843c30862 +clone git github.com/docker/go-connections v0.1.3 +clone git github.com/docker/engine-api 9a940e4ead265e18d4feb9e3c515428966a08278 clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de clone git github.com/imdario/mergo 0.2.1 diff --git a/vendor/src/github.com/Microsoft/go-winio/sd.go b/vendor/src/github.com/Microsoft/go-winio/sd.go index c8bc7ffa87..2df5a7c52b 100644 --- a/vendor/src/github.com/Microsoft/go-winio/sd.go +++ b/vendor/src/github.com/Microsoft/go-winio/sd.go @@ -65,7 +65,7 @@ func LookupSidByName(name string) (sid string, err error) { if err != nil { return "", &AccountLookupError{name, err} } - sid = syscall.UTF16ToString((*[1 << 30]uint16)(unsafe.Pointer(strBuffer))[:]) + sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:]) localFree(uintptr(unsafe.Pointer(strBuffer))) return sid, nil } diff --git a/vendor/src/github.com/docker/engine-api/client/client.go b/vendor/src/github.com/docker/engine-api/client/client.go index a62d859464..13aecc1be7 100644 --- a/vendor/src/github.com/docker/engine-api/client/client.go +++ b/vendor/src/github.com/docker/engine-api/client/client.go @@ -1,16 +1,14 @@ package client import ( - "crypto/tls" "fmt" - "net" "net/http" "net/url" "os" "path/filepath" "strings" - "time" + "github.com/docker/engine-api/client/transport" "github.com/docker/go-connections/tlsconfig" ) @@ -21,17 +19,13 @@ type Client struct { proto string // addr holds the client address. addr string - // basePath holds the path to prepend to the requests + // basePath holds the path to prepend to the requests. basePath string - // scheme holds the scheme of the client i.e. https. - scheme string - // tlsConfig holds the tls configuration to use in hijacked requests. - tlsConfig *tls.Config - // httpClient holds the client transport instance. Exported to keep the old code running. - httpClient *http.Client + // transport is the interface to sends request with, it implements transport.Client. + transport transport.Client // version of the server to talk to. version string - // custom http headers configured by users + // custom http headers configured by users. customHTTPHeaders map[string]string } @@ -41,7 +35,7 @@ type Client struct { // Use DOCKER_CERT_PATH to load the tls certificates from. // Use DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default. func NewEnvClient() (*Client, error) { - var transport *http.Transport + var client *http.Client if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" { options := tlsconfig.Options{ CAFile: filepath.Join(dockerCertPath, "ca.pem"), @@ -54,8 +48,10 @@ func NewEnvClient() (*Client, error) { return nil, err } - transport = &http.Transport{ - TLSClientConfig: tlsc, + client = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: tlsc, + }, } } @@ -63,42 +59,29 @@ func NewEnvClient() (*Client, error) { if host == "" { host = DefaultDockerHost } - return NewClient(host, os.Getenv("DOCKER_API_VERSION"), transport, nil) + return NewClient(host, os.Getenv("DOCKER_API_VERSION"), client, nil) } // NewClient initializes a new API client for the given host and API version. // It won't send any version information if the version number is empty. -// It uses the transport to create a new http client. +// It uses the given http client as transport. // It also initializes the custom http headers to add to each request. -func NewClient(host string, version string, transport *http.Transport, httpHeaders map[string]string) (*Client, error) { - var ( - basePath string - scheme = "http" - protoAddrParts = strings.SplitN(host, "://", 2) - proto, addr = protoAddrParts[0], protoAddrParts[1] - ) - - if proto == "tcp" { - parsed, err := url.Parse("tcp://" + addr) - if err != nil { - return nil, err - } - addr = parsed.Host - basePath = parsed.Path +func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) { + proto, addr, basePath, err := ParseHost(host) + if err != nil { + return nil, err } - transport = configureTransport(transport, proto, addr) - if transport.TLSClientConfig != nil { - scheme = "https" + transport, err := transport.NewTransportWithHTTP(proto, addr, client) + if err != nil { + return nil, err } return &Client{ proto: proto, addr: addr, basePath: basePath, - scheme: scheme, - tlsConfig: transport.TLSClientConfig, - httpClient: &http.Client{Transport: transport}, + transport: transport, version: version, customHTTPHeaders: httpHeaders, }, nil @@ -127,23 +110,22 @@ func (cli *Client) ClientVersion() string { return cli.version } -func configureTransport(tr *http.Transport, proto, addr string) *http.Transport { - if tr == nil { - tr = &http.Transport{} +// ParseHost verifies that the given host strings is valid. +func ParseHost(host string) (string, string, string, error) { + protoAddrParts := strings.SplitN(host, "://", 2) + if len(protoAddrParts) == 1 { + return "", "", "", fmt.Errorf("unable to parse docker host `%s`", host) } - // Why 32? See https://github.com/docker/docker/pull/8035. - timeout := 32 * time.Second - if proto == "unix" { - // No need for compression in local communications. - tr.DisableCompression = true - tr.Dial = func(_, _ string) (net.Conn, error) { - return net.DialTimeout(proto, addr, timeout) + var basePath string + proto, addr := protoAddrParts[0], protoAddrParts[1] + if proto == "tcp" { + parsed, err := url.Parse("tcp://" + addr) + if err != nil { + return "", "", "", err } - } else { - tr.Proxy = http.ProxyFromEnvironment - tr.Dial = (&net.Dialer{Timeout: timeout}).Dial + addr = parsed.Host + basePath = parsed.Path } - - return tr + return proto, addr, basePath, nil } diff --git a/vendor/src/github.com/docker/engine-api/client/client_unix.go b/vendor/src/github.com/docker/engine-api/client/client_unix.go index 39c4bd8f2c..a6d5390a7c 100644 --- a/vendor/src/github.com/docker/engine-api/client/client_unix.go +++ b/vendor/src/github.com/docker/engine-api/client/client_unix.go @@ -1,4 +1,4 @@ -// +build linux freebsd +// +build linux freebsd solaris package client diff --git a/vendor/src/github.com/docker/engine-api/client/container_stats.go b/vendor/src/github.com/docker/engine-api/client/container_stats.go index 486b8b0e7e..63b3d0e19f 100644 --- a/vendor/src/github.com/docker/engine-api/client/container_stats.go +++ b/vendor/src/github.com/docker/engine-api/client/container_stats.go @@ -3,18 +3,20 @@ package client import ( "io" "net/url" + + "golang.org/x/net/context" ) // ContainerStats returns near realtime stats for a given container. // It's up to the caller to close the io.ReadCloser returned. -func (cli *Client) ContainerStats(containerID string, stream bool) (io.ReadCloser, error) { +func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (io.ReadCloser, error) { query := url.Values{} query.Set("stream", "0") if stream { query.Set("stream", "1") } - resp, err := cli.get("/containers/"+containerID+"/stats", query, nil) + resp, err := cli.getWithContext(ctx, "/containers/"+containerID+"/stats", query, nil) if err != nil { return nil, err } diff --git a/vendor/src/github.com/docker/engine-api/client/copy.go b/vendor/src/github.com/docker/engine-api/client/copy.go index 92cf384a07..40d046268b 100644 --- a/vendor/src/github.com/docker/engine-api/client/copy.go +++ b/vendor/src/github.com/docker/engine-api/client/copy.go @@ -10,6 +10,8 @@ import ( "path/filepath" "strings" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" ) @@ -28,7 +30,7 @@ func (cli *Client) ContainerStatPath(containerID, path string) (types.ContainerP } // CopyToContainer copies content into the container filesystem. -func (cli *Client) CopyToContainer(options types.CopyToContainerOptions) error { +func (cli *Client) CopyToContainer(ctx context.Context, options types.CopyToContainerOptions) error { query := url.Values{} query.Set("path", filepath.ToSlash(options.Path)) // Normalize the paths used in the API. // Do not allow for an existing directory to be overwritten by a non-directory and vice versa. @@ -38,7 +40,7 @@ func (cli *Client) CopyToContainer(options types.CopyToContainerOptions) error { path := fmt.Sprintf("/containers/%s/archive", options.ContainerID) - response, err := cli.putRaw(path, query, options.Content, nil) + response, err := cli.putRawWithContext(ctx, path, query, options.Content, nil) if err != nil { return err } @@ -53,12 +55,12 @@ func (cli *Client) CopyToContainer(options types.CopyToContainerOptions) error { // CopyFromContainer get the content from the container and return it as a Reader // to manipulate it in the host. It's up to the caller to close the reader. -func (cli *Client) CopyFromContainer(containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) { +func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) { query := make(url.Values, 1) query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API. apiPath := fmt.Sprintf("/containers/%s/archive", containerID) - response, err := cli.get(apiPath, query, nil) + response, err := cli.getWithContext(ctx, apiPath, query, nil) if err != nil { return nil, types.ContainerPathStat{}, err } diff --git a/vendor/src/github.com/docker/engine-api/client/events.go b/vendor/src/github.com/docker/engine-api/client/events.go index 41f2f37334..75ba4e10e5 100644 --- a/vendor/src/github.com/docker/engine-api/client/events.go +++ b/vendor/src/github.com/docker/engine-api/client/events.go @@ -5,6 +5,8 @@ import ( "net/url" "time" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/filters" timetypes "github.com/docker/engine-api/types/time" @@ -12,7 +14,7 @@ import ( // Events returns a stream of events in the daemon in a ReadCloser. // It's up to the caller to close the stream. -func (cli *Client) Events(options types.EventsOptions) (io.ReadCloser, error) { +func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (io.ReadCloser, error) { query := url.Values{} ref := time.Now() @@ -38,7 +40,7 @@ func (cli *Client) Events(options types.EventsOptions) (io.ReadCloser, error) { query.Set("filters", filterJSON) } - serverResponse, err := cli.get("/events", query, nil) + serverResponse, err := cli.getWithContext(ctx, "/events", query, nil) if err != nil { return nil, err } diff --git a/vendor/src/github.com/docker/engine-api/client/export.go b/vendor/src/github.com/docker/engine-api/client/export.go index 2b67c21df2..952d85824d 100644 --- a/vendor/src/github.com/docker/engine-api/client/export.go +++ b/vendor/src/github.com/docker/engine-api/client/export.go @@ -3,13 +3,15 @@ package client import ( "io" "net/url" + + "golang.org/x/net/context" ) // ContainerExport retrieves the raw contents of a container // and returns them as a io.ReadCloser. It's up to the caller // to close the stream. -func (cli *Client) ContainerExport(containerID string) (io.ReadCloser, error) { - serverResp, err := cli.get("/containers/"+containerID+"/export", url.Values{}, nil) +func (cli *Client) ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) { + serverResp, err := cli.getWithContext(ctx, "/containers/"+containerID+"/export", url.Values{}, nil) if err != nil { return nil, err } diff --git a/vendor/src/github.com/docker/engine-api/client/hijack.go b/vendor/src/github.com/docker/engine-api/client/hijack.go index 5835d8c603..d40a136fdb 100644 --- a/vendor/src/github.com/docker/engine-api/client/hijack.go +++ b/vendor/src/github.com/docker/engine-api/client/hijack.go @@ -11,6 +11,7 @@ import ( "time" "github.com/docker/engine-api/types" + "github.com/docker/go-connections/sockets" ) // tlsClientCon holds tls information and a dialed connection. @@ -44,7 +45,7 @@ func (cli *Client) postHijacked(path string, query url.Values, body interface{}, req.Header.Set("Connection", "Upgrade") req.Header.Set("Upgrade", "tcp") - conn, err := dial(cli.proto, cli.addr, cli.tlsConfig) + conn, err := dial(cli.proto, cli.addr, cli.transport.TLSConfig()) if err != nil { if strings.Contains(err.Error(), "connection refused") { return types.HijackedResponse{}, fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?") @@ -156,9 +157,12 @@ func tlsDialWithDialer(dialer *net.Dialer, network, addr string, config *tls.Con } func dial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) { - if tlsConfig != nil && proto != "unix" { + if tlsConfig != nil && proto != "unix" && proto != "npipe" { // Notice this isn't Go standard's tls.Dial function return tlsDial(proto, addr, tlsConfig) } + if proto == "npipe" { + return sockets.DialPipe(addr, 32*time.Second) + } return net.Dial(proto, addr) } diff --git a/vendor/src/github.com/docker/engine-api/client/image_build.go b/vendor/src/github.com/docker/engine-api/client/image_build.go index 84e57fe68f..175d654fa9 100644 --- a/vendor/src/github.com/docker/engine-api/client/image_build.go +++ b/vendor/src/github.com/docker/engine-api/client/image_build.go @@ -9,6 +9,8 @@ import ( "strconv" "strings" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" ) @@ -18,7 +20,7 @@ var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`) // ImageBuild sends request to the daemon to build images. // The Body in the response implement an io.ReadCloser and it's up to the caller to // close it. -func (cli *Client) ImageBuild(options types.ImageBuildOptions) (types.ImageBuildResponse, error) { +func (cli *Client) ImageBuild(ctx context.Context, options types.ImageBuildOptions) (types.ImageBuildResponse, error) { query, err := imageBuildOptionsToQuery(options) if err != nil { return types.ImageBuildResponse{}, err @@ -32,7 +34,7 @@ func (cli *Client) ImageBuild(options types.ImageBuildOptions) (types.ImageBuild headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf)) headers.Set("Content-Type", "application/tar") - serverResp, err := cli.postRaw("/build", query, options.Context, headers) + serverResp, err := cli.postRaw(ctx, "/build", query, options.Context, headers) if err != nil { return types.ImageBuildResponse{}, err } diff --git a/vendor/src/github.com/docker/engine-api/client/image_create.go b/vendor/src/github.com/docker/engine-api/client/image_create.go index bd319228c5..ec2aa37c09 100644 --- a/vendor/src/github.com/docker/engine-api/client/image_create.go +++ b/vendor/src/github.com/docker/engine-api/client/image_create.go @@ -4,23 +4,25 @@ import ( "io" "net/url" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" ) // ImageCreate creates a new image based in the parent options. // It returns the JSON content in the response body. -func (cli *Client) ImageCreate(options types.ImageCreateOptions) (io.ReadCloser, error) { +func (cli *Client) ImageCreate(ctx context.Context, options types.ImageCreateOptions) (io.ReadCloser, error) { query := url.Values{} query.Set("fromImage", options.Parent) query.Set("tag", options.Tag) - resp, err := cli.tryImageCreate(query, options.RegistryAuth) + resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) if err != nil { return nil, err } return resp.body, nil } -func (cli *Client) tryImageCreate(query url.Values, registryAuth string) (*serverResponse, error) { +func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (*serverResponse, error) { headers := map[string][]string{"X-Registry-Auth": {registryAuth}} - return cli.post("/images/create", query, nil, headers) + return cli.postWithContext(ctx, "/images/create", query, nil, headers) } diff --git a/vendor/src/github.com/docker/engine-api/client/image_import.go b/vendor/src/github.com/docker/engine-api/client/image_import.go index 212a942a5f..48e2c951a4 100644 --- a/vendor/src/github.com/docker/engine-api/client/image_import.go +++ b/vendor/src/github.com/docker/engine-api/client/image_import.go @@ -4,12 +4,14 @@ import ( "io" "net/url" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" ) // ImageImport creates a new image based in the source options. // It returns the JSON content in the response body. -func (cli *Client) ImageImport(options types.ImageImportOptions) (io.ReadCloser, error) { +func (cli *Client) ImageImport(ctx context.Context, options types.ImageImportOptions) (io.ReadCloser, error) { query := url.Values{} query.Set("fromSrc", options.SourceName) query.Set("repo", options.RepositoryName) @@ -19,7 +21,7 @@ func (cli *Client) ImageImport(options types.ImageImportOptions) (io.ReadCloser, query.Add("changes", change) } - resp, err := cli.postRaw("/images/create", query, options.Source, nil) + resp, err := cli.postRaw(ctx, "/images/create", query, options.Source, nil) if err != nil { return nil, err } diff --git a/vendor/src/github.com/docker/engine-api/client/image_load.go b/vendor/src/github.com/docker/engine-api/client/image_load.go index ea6924a57b..0c8880cab0 100644 --- a/vendor/src/github.com/docker/engine-api/client/image_load.go +++ b/vendor/src/github.com/docker/engine-api/client/image_load.go @@ -4,14 +4,21 @@ import ( "io" "net/url" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" ) // ImageLoad loads an image in the docker host from the client host. // It's up to the caller to close the io.ReadCloser returned by // this function. -func (cli *Client) ImageLoad(input io.Reader) (types.ImageLoadResponse, error) { - resp, err := cli.postRaw("/images/load", url.Values{}, input, nil) +func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) { + v := url.Values{} + v.Set("quiet", "0") + if quiet { + v.Set("quiet", "1") + } + resp, err := cli.postRaw(ctx, "/images/load", v, input, nil) if err != nil { return types.ImageLoadResponse{}, err } diff --git a/vendor/src/github.com/docker/engine-api/client/image_pull.go b/vendor/src/github.com/docker/engine-api/client/image_pull.go index 69636925cb..0904437650 100644 --- a/vendor/src/github.com/docker/engine-api/client/image_pull.go +++ b/vendor/src/github.com/docker/engine-api/client/image_pull.go @@ -5,6 +5,8 @@ import ( "net/http" "net/url" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" ) @@ -12,20 +14,20 @@ import ( // It executes the privileged function if the operation is unauthorized // and it tries one more time. // It's up to the caller to handle the io.ReadCloser and close it properly. -func (cli *Client) ImagePull(options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) { +func (cli *Client) ImagePull(ctx context.Context, options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) { query := url.Values{} query.Set("fromImage", options.ImageID) if options.Tag != "" { query.Set("tag", options.Tag) } - resp, err := cli.tryImageCreate(query, options.RegistryAuth) + resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) if resp.statusCode == http.StatusUnauthorized { newAuthHeader, privilegeErr := privilegeFunc() if privilegeErr != nil { return nil, privilegeErr } - resp, err = cli.tryImageCreate(query, newAuthHeader) + resp, err = cli.tryImageCreate(ctx, query, newAuthHeader) } if err != nil { return nil, err diff --git a/vendor/src/github.com/docker/engine-api/client/image_push.go b/vendor/src/github.com/docker/engine-api/client/image_push.go index fe3877dd31..253e071f1f 100644 --- a/vendor/src/github.com/docker/engine-api/client/image_push.go +++ b/vendor/src/github.com/docker/engine-api/client/image_push.go @@ -5,6 +5,8 @@ import ( "net/http" "net/url" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" ) @@ -12,17 +14,17 @@ import ( // It executes the privileged function if the operation is unauthorized // and it tries one more time. // It's up to the caller to handle the io.ReadCloser and close it properly. -func (cli *Client) ImagePush(options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) { +func (cli *Client) ImagePush(ctx context.Context, options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) { query := url.Values{} query.Set("tag", options.Tag) - resp, err := cli.tryImagePush(options.ImageID, query, options.RegistryAuth) + resp, err := cli.tryImagePush(ctx, options.ImageID, query, options.RegistryAuth) if resp.statusCode == http.StatusUnauthorized { newAuthHeader, privilegeErr := privilegeFunc() if privilegeErr != nil { return nil, privilegeErr } - resp, err = cli.tryImagePush(options.ImageID, query, newAuthHeader) + resp, err = cli.tryImagePush(ctx, options.ImageID, query, newAuthHeader) } if err != nil { return nil, err @@ -30,7 +32,7 @@ func (cli *Client) ImagePush(options types.ImagePushOptions, privilegeFunc Reque return resp.body, nil } -func (cli *Client) tryImagePush(imageID string, query url.Values, registryAuth string) (*serverResponse, error) { +func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, registryAuth string) (*serverResponse, error) { headers := map[string][]string{"X-Registry-Auth": {registryAuth}} - return cli.post("/images/"+imageID+"/push", query, nil, headers) + return cli.postWithContext(ctx, "/images/"+imageID+"/push", query, nil, headers) } diff --git a/vendor/src/github.com/docker/engine-api/client/image_save.go b/vendor/src/github.com/docker/engine-api/client/image_save.go index 755d05412d..0ec7cac758 100644 --- a/vendor/src/github.com/docker/engine-api/client/image_save.go +++ b/vendor/src/github.com/docker/engine-api/client/image_save.go @@ -3,16 +3,18 @@ package client import ( "io" "net/url" + + "golang.org/x/net/context" ) // ImageSave retrieves one or more images from the docker host as a io.ReadCloser. // It's up to the caller to store the images and close the stream. -func (cli *Client) ImageSave(imageIDs []string) (io.ReadCloser, error) { +func (cli *Client) ImageSave(ctx context.Context, imageIDs []string) (io.ReadCloser, error) { query := url.Values{ "names": imageIDs, } - resp, err := cli.get("/images/get", query, nil) + resp, err := cli.getWithContext(ctx, "/images/get", query, nil) if err != nil { return nil, err } diff --git a/vendor/src/github.com/docker/engine-api/client/interface.go b/vendor/src/github.com/docker/engine-api/client/interface.go index 155a2bc448..26ad7a0b55 100644 --- a/vendor/src/github.com/docker/engine-api/client/interface.go +++ b/vendor/src/github.com/docker/engine-api/client/interface.go @@ -3,6 +3,8 @@ package client import ( "io" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" "github.com/docker/engine-api/types/filters" @@ -22,40 +24,40 @@ type APIClient interface { ContainerExecInspect(execID string) (types.ContainerExecInspect, error) ContainerExecResize(options types.ResizeOptions) error ContainerExecStart(execID string, config types.ExecStartCheck) error - ContainerExport(containerID string) (io.ReadCloser, error) + ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) ContainerInspect(containerID string) (types.ContainerJSON, error) ContainerInspectWithRaw(containerID string, getSize bool) (types.ContainerJSON, []byte, error) ContainerKill(containerID, signal string) error ContainerList(options types.ContainerListOptions) ([]types.Container, error) - ContainerLogs(options types.ContainerLogsOptions) (io.ReadCloser, error) + ContainerLogs(ctx context.Context, options types.ContainerLogsOptions) (io.ReadCloser, error) ContainerPause(containerID string) error ContainerRemove(options types.ContainerRemoveOptions) error ContainerRename(containerID, newContainerName string) error ContainerResize(options types.ResizeOptions) error ContainerRestart(containerID string, timeout int) error ContainerStatPath(containerID, path string) (types.ContainerPathStat, error) - ContainerStats(containerID string, stream bool) (io.ReadCloser, error) + ContainerStats(ctx context.Context, containerID string, stream bool) (io.ReadCloser, error) ContainerStart(containerID string) error ContainerStop(containerID string, timeout int) error ContainerTop(containerID string, arguments []string) (types.ContainerProcessList, error) ContainerUnpause(containerID string) error ContainerUpdate(containerID string, updateConfig container.UpdateConfig) error - ContainerWait(containerID string) (int, error) - CopyFromContainer(containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) - CopyToContainer(options types.CopyToContainerOptions) error - Events(options types.EventsOptions) (io.ReadCloser, error) - ImageBuild(options types.ImageBuildOptions) (types.ImageBuildResponse, error) - ImageCreate(options types.ImageCreateOptions) (io.ReadCloser, error) + ContainerWait(ctx context.Context, containerID string) (int, error) + CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) + CopyToContainer(ctx context.Context, options types.CopyToContainerOptions) error + Events(ctx context.Context, options types.EventsOptions) (io.ReadCloser, error) + ImageBuild(ctx context.Context, options types.ImageBuildOptions) (types.ImageBuildResponse, error) + ImageCreate(ctx context.Context, options types.ImageCreateOptions) (io.ReadCloser, error) ImageHistory(imageID string) ([]types.ImageHistory, error) - ImageImport(options types.ImageImportOptions) (io.ReadCloser, error) + ImageImport(ctx context.Context, options types.ImageImportOptions) (io.ReadCloser, error) ImageInspectWithRaw(imageID string, getSize bool) (types.ImageInspect, []byte, error) ImageList(options types.ImageListOptions) ([]types.Image, error) - ImageLoad(input io.Reader) (types.ImageLoadResponse, error) - ImagePull(options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) - ImagePush(options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) + ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) + ImagePull(ctx context.Context, options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) + ImagePush(ctx context.Context, options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) ImageRemove(options types.ImageRemoveOptions) ([]types.ImageDelete, error) ImageSearch(options types.ImageSearchOptions, privilegeFunc RequestPrivilegeFunc) ([]registry.SearchResult, error) - ImageSave(imageIDs []string) (io.ReadCloser, error) + ImageSave(ctx context.Context, imageIDs []string) (io.ReadCloser, error) ImageTag(options types.ImageTagOptions) error Info() (types.Info, error) NetworkConnect(networkID, containerID string, config *network.EndpointSettings) error diff --git a/vendor/src/github.com/docker/engine-api/client/logs.go b/vendor/src/github.com/docker/engine-api/client/logs.go index 58f1d97bd4..2aaf1839dc 100644 --- a/vendor/src/github.com/docker/engine-api/client/logs.go +++ b/vendor/src/github.com/docker/engine-api/client/logs.go @@ -5,13 +5,15 @@ import ( "net/url" "time" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" timetypes "github.com/docker/engine-api/types/time" ) // ContainerLogs returns the logs generated by a container in an io.ReadCloser. // It's up to the caller to close the stream. -func (cli *Client) ContainerLogs(options types.ContainerLogsOptions) (io.ReadCloser, error) { +func (cli *Client) ContainerLogs(ctx context.Context, options types.ContainerLogsOptions) (io.ReadCloser, error) { query := url.Values{} if options.ShowStdout { query.Set("stdout", "1") @@ -38,7 +40,7 @@ func (cli *Client) ContainerLogs(options types.ContainerLogsOptions) (io.ReadClo } query.Set("tail", options.Tail) - resp, err := cli.get("/containers/"+options.ContainerID+"/logs", query, nil) + resp, err := cli.getWithContext(ctx, "/containers/"+options.ContainerID+"/logs", query, nil) if err != nil { return nil, err } diff --git a/vendor/src/github.com/docker/engine-api/client/request.go b/vendor/src/github.com/docker/engine-api/client/request.go index cd8c3176d8..0432c73fce 100644 --- a/vendor/src/github.com/docker/engine-api/client/request.go +++ b/vendor/src/github.com/docker/engine-api/client/request.go @@ -9,6 +9,10 @@ import ( "net/http" "net/url" "strings" + + "github.com/docker/engine-api/client/transport/cancellable" + + "golang.org/x/net/context" ) // serverResponse is a wrapper for http API responses. @@ -20,40 +24,55 @@ type serverResponse struct { // head sends an http request to the docker API using the method HEAD. func (cli *Client) head(path string, query url.Values, headers map[string][]string) (*serverResponse, error) { - return cli.sendRequest("HEAD", path, query, nil, headers) + return cli.sendRequest(context.Background(), "HEAD", path, query, nil, headers) } // get sends an http request to the docker API using the method GET. func (cli *Client) get(path string, query url.Values, headers map[string][]string) (*serverResponse, error) { - return cli.sendRequest("GET", path, query, nil, headers) + return cli.getWithContext(context.Background(), path, query, headers) +} + +// getWithContext sends an http request to the docker API using the method GET with a specific go context. +func (cli *Client) getWithContext(ctx context.Context, path string, query url.Values, headers map[string][]string) (*serverResponse, error) { + return cli.sendRequest(ctx, "GET", path, query, nil, headers) } // post sends an http request to the docker API using the method POST. func (cli *Client) post(path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) { - return cli.sendRequest("POST", path, query, body, headers) + return cli.postWithContext(context.Background(), path, query, body, headers) } -// postRaw sends the raw input to the docker API using the method POST. -func (cli *Client) postRaw(path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) { - return cli.sendClientRequest("POST", path, query, body, headers) +// postWithContext sends an http request to the docker API using the method POST with a specific go context. +func (cli *Client) postWithContext(ctx context.Context, path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) { + return cli.sendRequest(ctx, "POST", path, query, body, headers) +} + +// postRaw sends the raw input to the docker API using the method POST with a specific go context. +func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) { + return cli.sendClientRequest(ctx, "POST", path, query, body, headers) } // put sends an http request to the docker API using the method PUT. func (cli *Client) put(path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) { - return cli.sendRequest("PUT", path, query, body, headers) + return cli.sendRequest(context.Background(), "PUT", path, query, body, headers) } // putRaw sends the raw input to the docker API using the method PUT. func (cli *Client) putRaw(path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) { - return cli.sendClientRequest("PUT", path, query, body, headers) + return cli.putRawWithContext(context.Background(), path, query, body, headers) +} + +// putRawWithContext sends the raw input to the docker API using the method PUT with a specific go context. +func (cli *Client) putRawWithContext(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) { + return cli.sendClientRequest(ctx, "PUT", path, query, body, headers) } // delete sends an http request to the docker API using the method DELETE. func (cli *Client) delete(path string, query url.Values, headers map[string][]string) (*serverResponse, error) { - return cli.sendRequest("DELETE", path, query, nil, headers) + return cli.sendRequest(context.Background(), "DELETE", path, query, nil, headers) } -func (cli *Client) sendRequest(method, path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) { +func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) { params, err := encodeData(body) if err != nil { return nil, err @@ -66,10 +85,10 @@ func (cli *Client) sendRequest(method, path string, query url.Values, body inter headers["Content-Type"] = []string{"application/json"} } - return cli.sendClientRequest(method, path, query, params, headers) + return cli.sendClientRequest(ctx, method, path, query, params, headers) } -func (cli *Client) sendClientRequest(method, path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) { +func (cli *Client) sendClientRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) { serverResp := &serverResponse{ body: nil, statusCode: -1, @@ -82,13 +101,13 @@ func (cli *Client) sendClientRequest(method, path string, query url.Values, body req, err := cli.newRequest(method, path, query, body, headers) req.URL.Host = cli.addr - req.URL.Scheme = cli.scheme + req.URL.Scheme = cli.transport.Scheme() if expectedPayload && req.Header.Get("Content-Type") == "" { req.Header.Set("Content-Type", "text/plain") } - resp, err := cli.httpClient.Do(req) + resp, err := cancellable.Do(ctx, cli.transport, req) if resp != nil { serverResp.statusCode = resp.StatusCode } @@ -98,10 +117,10 @@ func (cli *Client) sendClientRequest(method, path string, query url.Values, body return serverResp, ErrConnectionFailed } - if cli.scheme == "http" && strings.Contains(err.Error(), "malformed HTTP response") { + if !cli.transport.Secure() && strings.Contains(err.Error(), "malformed HTTP response") { return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err) } - if cli.scheme == "https" && strings.Contains(err.Error(), "remote error: bad certificate") { + if cli.transport.Secure() && strings.Contains(err.Error(), "remote error: bad certificate") { return serverResp, fmt.Errorf("The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: %v", err) } diff --git a/vendor/src/github.com/docker/engine-api/client/transport/cancellable/canceler.go b/vendor/src/github.com/docker/engine-api/client/transport/cancellable/canceler.go new file mode 100644 index 0000000000..11dff60026 --- /dev/null +++ b/vendor/src/github.com/docker/engine-api/client/transport/cancellable/canceler.go @@ -0,0 +1,23 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.5 + +package cancellable + +import ( + "net/http" + + "github.com/docker/engine-api/client/transport" +) + +func canceler(client transport.Sender, req *http.Request) func() { + // TODO(djd): Respect any existing value of req.Cancel. + ch := make(chan struct{}) + req.Cancel = ch + + return func() { + close(ch) + } +} diff --git a/vendor/src/github.com/docker/engine-api/client/transport/cancellable/canceler_go14.go b/vendor/src/github.com/docker/engine-api/client/transport/cancellable/canceler_go14.go new file mode 100644 index 0000000000..8ff2845c28 --- /dev/null +++ b/vendor/src/github.com/docker/engine-api/client/transport/cancellable/canceler_go14.go @@ -0,0 +1,27 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.5 + +package cancellable + +import ( + "net/http" + + "github.com/docker/engine-api/client/transport" +) + +type requestCanceler interface { + CancelRequest(*http.Request) +} + +func canceler(client transport.Sender, req *http.Request) func() { + rc, ok := client.(requestCanceler) + if !ok { + return func() {} + } + return func() { + rc.CancelRequest(req) + } +} diff --git a/vendor/src/github.com/docker/engine-api/client/transport/cancellable/cancellable.go b/vendor/src/github.com/docker/engine-api/client/transport/cancellable/cancellable.go new file mode 100644 index 0000000000..526feb0f45 --- /dev/null +++ b/vendor/src/github.com/docker/engine-api/client/transport/cancellable/cancellable.go @@ -0,0 +1,113 @@ +// Copyright 2015 The Go 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 cancellable provides helper function to cancel http requests. +package cancellable + +import ( + "io" + "net/http" + + "github.com/docker/engine-api/client/transport" + + "golang.org/x/net/context" +) + +func nop() {} + +var ( + testHookContextDoneBeforeHeaders = nop + testHookDoReturned = nop + testHookDidBodyClose = nop +) + +// Do sends an HTTP request with the provided transport.Sender and returns an HTTP response. +// If the client is nil, http.DefaultClient is used. +// If the context is canceled or times out, ctx.Err() will be returned. +// +// FORK INFORMATION: +// +// This function deviates from the upstream version in golang.org/x/net/context/ctxhttp by +// taking a Sender interface rather than a *http.Client directly. That allow us to use +// this funcion with mocked clients and hijacked connections. +func Do(ctx context.Context, client transport.Sender, req *http.Request) (*http.Response, error) { + if client == nil { + client = http.DefaultClient + } + + // Request cancelation changed in Go 1.5, see canceler.go and canceler_go14.go. + cancel := canceler(client, req) + + type responseAndError struct { + resp *http.Response + err error + } + result := make(chan responseAndError, 1) + + go func() { + resp, err := client.Do(req) + testHookDoReturned() + result <- responseAndError{resp, err} + }() + + var resp *http.Response + + select { + case <-ctx.Done(): + testHookContextDoneBeforeHeaders() + cancel() + // Clean up after the goroutine calling client.Do: + go func() { + if r := <-result; r.resp != nil && r.resp.Body != nil { + testHookDidBodyClose() + r.resp.Body.Close() + } + }() + return nil, ctx.Err() + case r := <-result: + var err error + resp, err = r.resp, r.err + if err != nil { + return resp, err + } + } + + c := make(chan struct{}) + go func() { + select { + case <-ctx.Done(): + cancel() + case <-c: + // The response's Body is closed. + } + }() + resp.Body = ¬ifyingReader{resp.Body, c} + + return resp, nil +} + +// notifyingReader is an io.ReadCloser that closes the notify channel after +// Close is called or a Read fails on the underlying ReadCloser. +type notifyingReader struct { + io.ReadCloser + notify chan<- struct{} +} + +func (r *notifyingReader) Read(p []byte) (int, error) { + n, err := r.ReadCloser.Read(p) + if err != nil && r.notify != nil { + close(r.notify) + r.notify = nil + } + return n, err +} + +func (r *notifyingReader) Close() error { + err := r.ReadCloser.Close() + if r.notify != nil { + close(r.notify) + r.notify = nil + } + return err +} diff --git a/vendor/src/github.com/docker/engine-api/client/transport/client.go b/vendor/src/github.com/docker/engine-api/client/transport/client.go new file mode 100644 index 0000000000..13d4b3ab3d --- /dev/null +++ b/vendor/src/github.com/docker/engine-api/client/transport/client.go @@ -0,0 +1,47 @@ +package transport + +import ( + "crypto/tls" + "net/http" +) + +// Sender is an interface that clients must implement +// to be able to send requests to a remote connection. +type Sender interface { + // Do sends request to a remote endpoint. + Do(*http.Request) (*http.Response, error) +} + +// Client is an interface that abstracts all remote connections. +type Client interface { + Sender + // Secure tells whether the connection is secure or not. + Secure() bool + // Scheme returns the connection protocol the client uses. + Scheme() string + // TLSConfig returns any TLS configuration the client uses. + TLSConfig() *tls.Config +} + +// tlsInfo returns information about the TLS configuration. +type tlsInfo struct { + tlsConfig *tls.Config +} + +// TLSConfig returns the TLS configuration. +func (t *tlsInfo) TLSConfig() *tls.Config { + return t.tlsConfig +} + +// Scheme returns protocol scheme to use. +func (t *tlsInfo) Scheme() string { + if t.tlsConfig != nil { + return "https" + } + return "http" +} + +// Secure returns true if there is a TLS configuration. +func (t *tlsInfo) Secure() bool { + return t.tlsConfig != nil +} diff --git a/vendor/src/github.com/docker/engine-api/client/transport/client_mock.go b/vendor/src/github.com/docker/engine-api/client/transport/client_mock.go new file mode 100644 index 0000000000..8cc0cca5b1 --- /dev/null +++ b/vendor/src/github.com/docker/engine-api/client/transport/client_mock.go @@ -0,0 +1,26 @@ +// +build test + +package transport + +import ( + "crypto/tls" + "net/http" +) + +type mockClient struct { + *tlsInfo + do func(*http.Request) (*http.Response, error) +} + +// NewMockClient returns a mocked client that runs the function supplied as `client.Do` call +func NewMockClient(tlsConfig *tls.Config, doer func(*http.Request) (*http.Response, error)) Client { + return mockClient{ + tlsInfo: &tlsInfo{tlsConfig}, + do: doer, + } +} + +// Do executes the supplied function for the mock. +func (m mockClient) Do(req *http.Request) (*http.Response, error) { + return m.do(req) +} diff --git a/vendor/src/github.com/docker/engine-api/client/transport/transport.go b/vendor/src/github.com/docker/engine-api/client/transport/transport.go new file mode 100644 index 0000000000..ff28af1855 --- /dev/null +++ b/vendor/src/github.com/docker/engine-api/client/transport/transport.go @@ -0,0 +1,57 @@ +// Package transport provides function to send request to remote endpoints. +package transport + +import ( + "fmt" + "net/http" + + "github.com/docker/go-connections/sockets" +) + +// apiTransport holds information about the http transport to connect with the API. +type apiTransport struct { + *http.Client + *tlsInfo + transport *http.Transport +} + +// NewTransportWithHTTP creates a new transport based on the provided proto, address and http client. +// It uses Docker's default http transport configuration if the client is nil. +// It does not modify the client's transport if it's not nil. +func NewTransportWithHTTP(proto, addr string, client *http.Client) (Client, error) { + var transport *http.Transport + + if client != nil { + tr, ok := client.Transport.(*http.Transport) + if !ok { + return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", client.Transport) + } + transport = tr + } else { + transport = defaultTransport(proto, addr) + client = &http.Client{ + Transport: transport, + } + } + + return &apiTransport{ + Client: client, + tlsInfo: &tlsInfo{transport.TLSClientConfig}, + transport: transport, + }, nil +} + +// CancelRequest stops a request execution. +func (a *apiTransport) CancelRequest(req *http.Request) { + a.transport.CancelRequest(req) +} + +// defaultTransport creates a new http.Transport with Docker's +// default transport configuration. +func defaultTransport(proto, addr string) *http.Transport { + tr := new(http.Transport) + sockets.ConfigureTransport(tr, proto, addr) + return tr +} + +var _ Client = &apiTransport{} diff --git a/vendor/src/github.com/docker/engine-api/client/wait.go b/vendor/src/github.com/docker/engine-api/client/wait.go index 17cb1d8ab5..ed7cbfaa78 100644 --- a/vendor/src/github.com/docker/engine-api/client/wait.go +++ b/vendor/src/github.com/docker/engine-api/client/wait.go @@ -3,13 +3,15 @@ package client import ( "encoding/json" + "golang.org/x/net/context" + "github.com/docker/engine-api/types" ) // ContainerWait pauses execution util a container is exits. // It returns the API status code as response of its readiness. -func (cli *Client) ContainerWait(containerID string) (int, error) { - resp, err := cli.post("/containers/"+containerID+"/wait", nil, nil, nil) +func (cli *Client) ContainerWait(ctx context.Context, containerID string) (int, error) { + resp, err := cli.postWithContext(ctx, "/containers/"+containerID+"/wait", nil, nil, nil) if err != nil { return -1, err } diff --git a/vendor/src/github.com/docker/engine-api/types/container/hostconfig_unix.go b/vendor/src/github.com/docker/engine-api/types/container/hostconfig_unix.go index 775e903f1c..c12534aec4 100644 --- a/vendor/src/github.com/docker/engine-api/types/container/hostconfig_unix.go +++ b/vendor/src/github.com/docker/engine-api/types/container/hostconfig_unix.go @@ -72,12 +72,6 @@ func (n NetworkMode) IsUserDefined() bool { return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() } -// IsPreDefinedNetwork indicates if a network is predefined by the daemon -func IsPreDefinedNetwork(network string) bool { - n := NetworkMode(network) - return n.IsBridge() || n.IsHost() || n.IsNone() -} - //UserDefined indicates user-created network func (n NetworkMode) UserDefined() string { if n.IsUserDefined() { diff --git a/vendor/src/github.com/docker/engine-api/types/container/hostconfig_windows.go b/vendor/src/github.com/docker/engine-api/types/container/hostconfig_windows.go index 0140c9575b..64ba756d2b 100644 --- a/vendor/src/github.com/docker/engine-api/types/container/hostconfig_windows.go +++ b/vendor/src/github.com/docker/engine-api/types/container/hostconfig_windows.go @@ -49,11 +49,6 @@ func (n NetworkMode) NetworkName() string { return "" } -// IsPreDefinedNetwork indicates if a network is predefined by the daemon -func IsPreDefinedNetwork(network string) bool { - return false -} - // ValidateNetMode ensures that the various combinations of requested // network settings are valid. func ValidateNetMode(c *Config, hc *HostConfig) error { diff --git a/vendor/src/github.com/docker/engine-api/types/types.go b/vendor/src/github.com/docker/engine-api/types/types.go index de8b0becc9..efb5a606c8 100644 --- a/vendor/src/github.com/docker/engine-api/types/types.go +++ b/vendor/src/github.com/docker/engine-api/types/types.go @@ -387,6 +387,7 @@ type NetworkResource struct { ID string `json:"Id"` Scope string Driver string + EnableIPv6 bool IPAM network.IPAM Internal bool Containers map[string]EndpointResource @@ -407,6 +408,7 @@ type NetworkCreate struct { Name string CheckDuplicate bool Driver string + EnableIPv6 bool IPAM network.IPAM Internal bool Options map[string]string diff --git a/vendor/src/github.com/docker/go-connections/sockets/inmem_socket.go b/vendor/src/github.com/docker/go-connections/sockets/inmem_socket.go new file mode 100644 index 0000000000..3395e40229 --- /dev/null +++ b/vendor/src/github.com/docker/go-connections/sockets/inmem_socket.go @@ -0,0 +1,89 @@ +package sockets + +import ( + "errors" + "net" + "sync" +) + +var errClosed = errors.New("use of closed network connection") + +// InmemSocket implements net.Listener using in-memory only connections. +type InmemSocket struct { + chConn chan net.Conn + chClose chan struct{} + addr string + mu sync.Mutex +} + +// dummyAddr is used to satisfy net.Addr for the in-mem socket +// it is just stored as a string and returns the string for all calls +type dummyAddr string + +// NewInmemSocket creates an in-memory only net.Listener +// The addr argument can be any string, but is used to satisfy the `Addr()` part +// of the net.Listener interface +func NewInmemSocket(addr string, bufSize int) *InmemSocket { + return &InmemSocket{ + chConn: make(chan net.Conn, bufSize), + chClose: make(chan struct{}), + addr: addr, + } +} + +// Addr returns the socket's addr string to satisfy net.Listener +func (s *InmemSocket) Addr() net.Addr { + return dummyAddr(s.addr) +} + +// Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn. +func (s *InmemSocket) Accept() (net.Conn, error) { + select { + case conn := <-s.chConn: + return conn, nil + case <-s.chClose: + return nil, errClosed + } +} + +// Close closes the listener. It will be unavailable for use once closed. +func (s *InmemSocket) Close() error { + s.mu.Lock() + defer s.mu.Unlock() + select { + case <-s.chClose: + default: + close(s.chClose) + } + return nil +} + +// Dial is used to establish a connection with the in-mem server +func (s *InmemSocket) Dial(network, addr string) (net.Conn, error) { + srvConn, clientConn := net.Pipe() + select { + case s.chConn <- srvConn: + case <-s.chClose: + return nil, errClosed + } + + return clientConn, nil +} + +// Network returns the addr string, satisfies net.Addr +func (a dummyAddr) Network() string { + return string(a) +} + +// String returns the string form +func (a dummyAddr) String() string { + return string(a) +} + +// timeoutError is used when there is a timeout with a connection +// this implements the net.Error interface +type timeoutError struct{} + +func (e *timeoutError) Error() string { return "i/o timeout" } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } diff --git a/vendor/src/github.com/docker/go-connections/sockets/sockets.go b/vendor/src/github.com/docker/go-connections/sockets/sockets.go new file mode 100644 index 0000000000..4bf5e84fc1 --- /dev/null +++ b/vendor/src/github.com/docker/go-connections/sockets/sockets.go @@ -0,0 +1,35 @@ +// Package sockets provides helper functions to create and configure Unix or TCP sockets. +package sockets + +import ( + "net" + "net/http" + "time" +) + +// Why 32? See https://github.com/docker/docker/pull/8035. +const defaulTimeout = 32 * time.Second + +// ConfigureTransport configures the specified Transport according to the +// specified proto and addr. +// If the proto is unix (using a unix socket to communicate) the compression +// is disabled. +func ConfigureTransport(tr *http.Transport, proto, addr string) { + switch proto { + case "unix": + // No need for compression in local communications. + tr.DisableCompression = true + tr.Dial = func(_, _ string) (net.Conn, error) { + return net.DialTimeout(proto, addr, defaulTimeout) + } + case "npipe": + // No need for compression in local communications. + tr.DisableCompression = true + tr.Dial = func(_, _ string) (net.Conn, error) { + return DialPipe(addr, defaulTimeout) + } + default: + tr.Proxy = http.ProxyFromEnvironment + tr.Dial = (&net.Dialer{Timeout: defaulTimeout}).Dial + } +} diff --git a/vendor/src/github.com/docker/go-connections/sockets/sockets_unix.go b/vendor/src/github.com/docker/go-connections/sockets/sockets_unix.go new file mode 100644 index 0000000000..b255ac9ac7 --- /dev/null +++ b/vendor/src/github.com/docker/go-connections/sockets/sockets_unix.go @@ -0,0 +1,15 @@ +// +build !windows + +package sockets + +import ( + "net" + "syscall" + "time" +) + +// DialPipe connects to a Windows named pipe. +// This is not supported on other OSes. +func DialPipe(_ string, _ time.Duration) (net.Conn, error) { + return nil, syscall.EAFNOSUPPORT +} diff --git a/vendor/src/github.com/docker/go-connections/sockets/sockets_windows.go b/vendor/src/github.com/docker/go-connections/sockets/sockets_windows.go new file mode 100644 index 0000000000..1f3540b2fe --- /dev/null +++ b/vendor/src/github.com/docker/go-connections/sockets/sockets_windows.go @@ -0,0 +1,13 @@ +package sockets + +import ( + "net" + "time" + + "github.com/Microsoft/go-winio" +) + +// DialPipe connects to a Windows named pipe. +func DialPipe(addr string, timeout time.Duration) (net.Conn, error) { + return winio.DialPipe(addr, &timeout) +} diff --git a/vendor/src/github.com/docker/go-connections/sockets/tcp_socket.go b/vendor/src/github.com/docker/go-connections/sockets/tcp_socket.go index 5d80e4a305..8a82727df0 100644 --- a/vendor/src/github.com/docker/go-connections/sockets/tcp_socket.go +++ b/vendor/src/github.com/docker/go-connections/sockets/tcp_socket.go @@ -4,8 +4,6 @@ package sockets import ( "crypto/tls" "net" - "net/http" - "time" ) // NewTCPSocket creates a TCP socket listener with the specified address and @@ -22,22 +20,3 @@ func NewTCPSocket(addr string, tlsConfig *tls.Config) (net.Listener, error) { } return l, nil } - -// ConfigureTCPTransport configures the specified Transport according to the -// specified proto and addr. -// If the proto is unix (using a unix socket to communicate) the compression -// is disabled. -func ConfigureTCPTransport(tr *http.Transport, proto, addr string) { - // Why 32? See https://github.com/docker/docker/pull/8035. - timeout := 32 * time.Second - if proto == "unix" { - // No need for compression in local communications. - tr.DisableCompression = true - tr.Dial = func(_, _ string) (net.Conn, error) { - return net.DialTimeout(proto, addr, timeout) - } - } else { - tr.Proxy = http.ProxyFromEnvironment - tr.Dial = (&net.Dialer{Timeout: timeout}).Dial - } -} diff --git a/vendor/src/github.com/docker/go-connections/tlsconfig/config.go b/vendor/src/github.com/docker/go-connections/tlsconfig/config.go index e3dfad1f0e..9378c358e6 100644 --- a/vendor/src/github.com/docker/go-connections/tlsconfig/config.go +++ b/vendor/src/github.com/docker/go-connections/tlsconfig/config.go @@ -41,12 +41,6 @@ var acceptedCBCCiphers = []uint16{ tls.TLS_RSA_WITH_AES_128_CBC_SHA, } -// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) -var clientCipherSuites = []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, -} - // DefaultServerAcceptedCiphers should be uses by code which already has a crypto/tls // options struct but wants to use a commonly accepted set of TLS cipher suites, with // known weak algorithms removed. @@ -91,7 +85,7 @@ func certPool(caFile string) (*x509.CertPool, error) { func Client(options Options) (*tls.Config, error) { tlsConfig := ClientDefault tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify - if !options.InsecureSkipVerify { + if !options.InsecureSkipVerify && options.CAFile != "" { CAs, err := certPool(options.CAFile) if err != nil { return nil, err @@ -99,7 +93,7 @@ func Client(options Options) (*tls.Config, error) { tlsConfig.RootCAs = CAs } - if options.CertFile != "" && options.KeyFile != "" { + if options.CertFile != "" || options.KeyFile != "" { tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile) if err != nil { return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err) diff --git a/vendor/src/github.com/docker/go-connections/tlsconfig/config_client_ciphers.go b/vendor/src/github.com/docker/go-connections/tlsconfig/config_client_ciphers.go new file mode 100644 index 0000000000..6b4c6a7c0d --- /dev/null +++ b/vendor/src/github.com/docker/go-connections/tlsconfig/config_client_ciphers.go @@ -0,0 +1,17 @@ +// +build go1.5 + +// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. +// +package tlsconfig + +import ( + "crypto/tls" +) + +// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) +var clientCipherSuites = []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, +} diff --git a/vendor/src/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go b/vendor/src/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go new file mode 100644 index 0000000000..ee22df47cb --- /dev/null +++ b/vendor/src/github.com/docker/go-connections/tlsconfig/config_legacy_client_ciphers.go @@ -0,0 +1,15 @@ +// +build !go1.5 + +// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. +// +package tlsconfig + +import ( + "crypto/tls" +) + +// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) +var clientCipherSuites = []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, +}