Vendor engine-api with client context changes.
| ... | ... |
@@ -14,6 +14,8 @@ import ( |
| 14 | 14 |
"runtime" |
| 15 | 15 |
"strings" |
| 16 | 16 |
|
| 17 |
+ "golang.org/x/net/context" |
|
| 18 |
+ |
|
| 17 | 19 |
"github.com/docker/docker/api" |
| 18 | 20 |
"github.com/docker/docker/builder/dockerignore" |
| 19 | 21 |
Cli "github.com/docker/docker/cli" |
| ... | ... |
@@ -77,8 +79,8 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 77 | 77 |
cmd.ParseFlags(args, true) |
| 78 | 78 |
|
| 79 | 79 |
var ( |
| 80 |
- context io.ReadCloser |
|
| 81 |
- err error |
|
| 80 |
+ ctx io.ReadCloser |
|
| 81 |
+ err error |
|
| 82 | 82 |
) |
| 83 | 83 |
|
| 84 | 84 |
specifiedContext := cmd.Arg(0) |
| ... | ... |
@@ -100,11 +102,11 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 100 | 100 |
|
| 101 | 101 |
switch {
|
| 102 | 102 |
case specifiedContext == "-": |
| 103 |
- context, relDockerfile, err = getContextFromReader(cli.in, *dockerfileName) |
|
| 103 |
+ ctx, relDockerfile, err = getContextFromReader(cli.in, *dockerfileName) |
|
| 104 | 104 |
case urlutil.IsGitURL(specifiedContext): |
| 105 | 105 |
tempDir, relDockerfile, err = getContextFromGitURL(specifiedContext, *dockerfileName) |
| 106 | 106 |
case urlutil.IsURL(specifiedContext): |
| 107 |
- context, relDockerfile, err = getContextFromURL(progBuff, specifiedContext, *dockerfileName) |
|
| 107 |
+ ctx, relDockerfile, err = getContextFromURL(progBuff, specifiedContext, *dockerfileName) |
|
| 108 | 108 |
default: |
| 109 | 109 |
contextDir, relDockerfile, err = getContextFromLocalDir(specifiedContext, *dockerfileName) |
| 110 | 110 |
} |
| ... | ... |
@@ -121,7 +123,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 121 | 121 |
contextDir = tempDir |
| 122 | 122 |
} |
| 123 | 123 |
|
| 124 |
- if context == nil {
|
|
| 124 |
+ if ctx == nil {
|
|
| 125 | 125 |
// And canonicalize dockerfile name to a platform-independent one |
| 126 | 126 |
relDockerfile, err = archive.CanonicalTarNameForPath(relDockerfile) |
| 127 | 127 |
if err != nil {
|
| ... | ... |
@@ -159,7 +161,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 159 | 159 |
includes = append(includes, ".dockerignore", relDockerfile) |
| 160 | 160 |
} |
| 161 | 161 |
|
| 162 |
- context, err = archive.TarWithOptions(contextDir, &archive.TarOptions{
|
|
| 162 |
+ ctx, err = archive.TarWithOptions(contextDir, &archive.TarOptions{
|
|
| 163 | 163 |
Compression: archive.Uncompressed, |
| 164 | 164 |
ExcludePatterns: excludes, |
| 165 | 165 |
IncludeFiles: includes, |
| ... | ... |
@@ -173,13 +175,13 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 173 | 173 |
if isTrusted() {
|
| 174 | 174 |
// Wrap the tar archive to replace the Dockerfile entry with the rewritten |
| 175 | 175 |
// Dockerfile which uses trusted pulls. |
| 176 |
- context = replaceDockerfileTarWrapper(context, relDockerfile, cli.trustedReference, &resolvedTags) |
|
| 176 |
+ ctx = replaceDockerfileTarWrapper(ctx, relDockerfile, cli.trustedReference, &resolvedTags) |
|
| 177 | 177 |
} |
| 178 | 178 |
|
| 179 | 179 |
// Setup an upload progress bar |
| 180 | 180 |
progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(progBuff, true) |
| 181 | 181 |
|
| 182 |
- var body io.Reader = progress.NewProgressReader(context, progressOutput, 0, "", "Sending build context to Docker daemon") |
|
| 182 |
+ var body io.Reader = progress.NewProgressReader(ctx, progressOutput, 0, "", "Sending build context to Docker daemon") |
|
| 183 | 183 |
|
| 184 | 184 |
var memory int64 |
| 185 | 185 |
if *flMemoryString != "" {
|
| ... | ... |
@@ -235,7 +237,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
| 235 | 235 |
AuthConfigs: cli.configFile.AuthConfigs, |
| 236 | 236 |
} |
| 237 | 237 |
|
| 238 |
- response, err := cli.client.ImageBuild(options) |
|
| 238 |
+ response, err := cli.client.ImageBuild(context.Background(), options) |
|
| 239 | 239 |
if err != nil {
|
| 240 | 240 |
return err |
| 241 | 241 |
} |
| ... | ... |
@@ -15,6 +15,7 @@ import ( |
| 15 | 15 |
"github.com/docker/docker/opts" |
| 16 | 16 |
"github.com/docker/docker/pkg/term" |
| 17 | 17 |
"github.com/docker/engine-api/client" |
| 18 |
+ "github.com/docker/go-connections/sockets" |
|
| 18 | 19 |
"github.com/docker/go-connections/tlsconfig" |
| 19 | 20 |
) |
| 20 | 21 |
|
| ... | ... |
@@ -142,12 +143,12 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF |
| 142 | 142 |
verStr = tmpStr |
| 143 | 143 |
} |
| 144 | 144 |
|
| 145 |
- clientTransport, err := newClientTransport(clientFlags.Common.TLSOptions) |
|
| 145 |
+ httpClient, err := newHTTPClient(host, clientFlags.Common.TLSOptions) |
|
| 146 | 146 |
if err != nil {
|
| 147 | 147 |
return err |
| 148 | 148 |
} |
| 149 | 149 |
|
| 150 |
- client, err := client.NewClient(host, verStr, clientTransport, customHeaders) |
|
| 150 |
+ client, err := client.NewClient(host, verStr, httpClient, customHeaders) |
|
| 151 | 151 |
if err != nil {
|
| 152 | 152 |
return err |
| 153 | 153 |
} |
| ... | ... |
@@ -180,16 +181,27 @@ func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (host string, |
| 180 | 180 |
return |
| 181 | 181 |
} |
| 182 | 182 |
|
| 183 |
-func newClientTransport(tlsOptions *tlsconfig.Options) (*http.Transport, error) {
|
|
| 183 |
+func newHTTPClient(host string, tlsOptions *tlsconfig.Options) (*http.Client, error) {
|
|
| 184 | 184 |
if tlsOptions == nil {
|
| 185 |
- return &http.Transport{}, nil
|
|
| 185 |
+ // let the api client configure the default transport. |
|
| 186 |
+ return nil, nil |
|
| 186 | 187 |
} |
| 187 | 188 |
|
| 188 | 189 |
config, err := tlsconfig.Client(*tlsOptions) |
| 189 | 190 |
if err != nil {
|
| 190 | 191 |
return nil, err |
| 191 | 192 |
} |
| 192 |
- return &http.Transport{
|
|
| 193 |
+ tr := &http.Transport{
|
|
| 193 | 194 |
TLSClientConfig: config, |
| 195 |
+ } |
|
| 196 |
+ proto, addr, _, err := client.ParseHost(host) |
|
| 197 |
+ if err != nil {
|
|
| 198 |
+ return nil, err |
|
| 199 |
+ } |
|
| 200 |
+ |
|
| 201 |
+ sockets.ConfigureTransport(tr, proto, addr) |
|
| 202 |
+ |
|
| 203 |
+ return &http.Client{
|
|
| 204 |
+ Transport: tr, |
|
| 194 | 205 |
}, nil |
| 195 | 206 |
} |
| ... | ... |
@@ -7,6 +7,8 @@ import ( |
| 7 | 7 |
"path/filepath" |
| 8 | 8 |
"strings" |
| 9 | 9 |
|
| 10 |
+ "golang.org/x/net/context" |
|
| 11 |
+ |
|
| 10 | 12 |
Cli "github.com/docker/docker/cli" |
| 11 | 13 |
"github.com/docker/docker/pkg/archive" |
| 12 | 14 |
flag "github.com/docker/docker/pkg/mflag" |
| ... | ... |
@@ -165,7 +167,7 @@ func (cli *DockerCli) copyFromContainer(srcContainer, srcPath, dstPath string, c |
| 165 | 165 |
|
| 166 | 166 |
} |
| 167 | 167 |
|
| 168 |
- content, stat, err := cli.client.CopyFromContainer(srcContainer, srcPath) |
|
| 168 |
+ content, stat, err := cli.client.CopyFromContainer(context.Background(), srcContainer, srcPath) |
|
| 169 | 169 |
if err != nil {
|
| 170 | 170 |
return err |
| 171 | 171 |
} |
| ... | ... |
@@ -292,5 +294,5 @@ func (cli *DockerCli) copyToContainer(srcPath, dstContainer, dstPath string, cpP |
| 292 | 292 |
AllowOverwriteDirWithFile: false, |
| 293 | 293 |
} |
| 294 | 294 |
|
| 295 |
- return cli.client.CopyToContainer(options) |
|
| 295 |
+ return cli.client.CopyToContainer(context.Background(), options) |
|
| 296 | 296 |
} |
| ... | ... |
@@ -5,6 +5,8 @@ import ( |
| 5 | 5 |
"io" |
| 6 | 6 |
"os" |
| 7 | 7 |
|
| 8 |
+ "golang.org/x/net/context" |
|
| 9 |
+ |
|
| 8 | 10 |
Cli "github.com/docker/docker/cli" |
| 9 | 11 |
"github.com/docker/docker/pkg/jsonmessage" |
| 10 | 12 |
"github.com/docker/docker/reference" |
| ... | ... |
@@ -52,7 +54,7 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
|
| 52 | 52 |
RegistryAuth: encodedAuth, |
| 53 | 53 |
} |
| 54 | 54 |
|
| 55 |
- responseBody, err := cli.client.ImageCreate(options) |
|
| 55 |
+ responseBody, err := cli.client.ImageCreate(context.Background(), options) |
|
| 56 | 56 |
if err != nil {
|
| 57 | 57 |
return err |
| 58 | 58 |
} |
| ... | ... |
@@ -8,6 +8,8 @@ import ( |
| 8 | 8 |
"strings" |
| 9 | 9 |
"time" |
| 10 | 10 |
|
| 11 |
+ "golang.org/x/net/context" |
|
| 12 |
+ |
|
| 11 | 13 |
Cli "github.com/docker/docker/cli" |
| 12 | 14 |
"github.com/docker/docker/opts" |
| 13 | 15 |
"github.com/docker/docker/pkg/jsonlog" |
| ... | ... |
@@ -48,7 +50,7 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
|
| 48 | 48 |
Filters: eventFilterArgs, |
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 |
- responseBody, err := cli.client.Events(options) |
|
| 51 |
+ responseBody, err := cli.client.Events(context.Background(), options) |
|
| 52 | 52 |
if err != nil {
|
| 53 | 53 |
return err |
| 54 | 54 |
} |
| ... | ... |
@@ -4,6 +4,8 @@ import ( |
| 4 | 4 |
"errors" |
| 5 | 5 |
"io" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
Cli "github.com/docker/docker/cli" |
| 8 | 10 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 11 |
) |
| ... | ... |
@@ -24,7 +26,7 @@ func (cli *DockerCli) CmdExport(args ...string) error {
|
| 24 | 24 |
return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
|
| 25 | 25 |
} |
| 26 | 26 |
|
| 27 |
- responseBody, err := cli.client.ContainerExport(cmd.Arg(0)) |
|
| 27 |
+ responseBody, err := cli.client.ContainerExport(context.Background(), cmd.Arg(0)) |
|
| 28 | 28 |
if err != nil {
|
| 29 | 29 |
return err |
| 30 | 30 |
} |
| ... | ... |
@@ -5,6 +5,8 @@ import ( |
| 5 | 5 |
"io" |
| 6 | 6 |
"os" |
| 7 | 7 |
|
| 8 |
+ "golang.org/x/net/context" |
|
| 9 |
+ |
|
| 8 | 10 |
Cli "github.com/docker/docker/cli" |
| 9 | 11 |
"github.com/docker/docker/opts" |
| 10 | 12 |
"github.com/docker/docker/pkg/jsonmessage" |
| ... | ... |
@@ -70,7 +72,7 @@ func (cli *DockerCli) CmdImport(args ...string) error {
|
| 70 | 70 |
Changes: changes, |
| 71 | 71 |
} |
| 72 | 72 |
|
| 73 |
- responseBody, err := cli.client.ImageImport(options) |
|
| 73 |
+ responseBody, err := cli.client.ImageImport(context.Background(), options) |
|
| 74 | 74 |
if err != nil {
|
| 75 | 75 |
return err |
| 76 | 76 |
} |
| ... | ... |
@@ -4,6 +4,8 @@ import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
"os" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
Cli "github.com/docker/docker/cli" |
| 8 | 10 |
"github.com/docker/docker/pkg/jsonmessage" |
| 9 | 11 |
flag "github.com/docker/docker/pkg/mflag" |
| ... | ... |
@@ -30,7 +32,7 @@ func (cli *DockerCli) CmdLoad(args ...string) error {
|
| 30 | 30 |
input = file |
| 31 | 31 |
} |
| 32 | 32 |
|
| 33 |
- response, err := cli.client.ImageLoad(input) |
|
| 33 |
+ response, err := cli.client.ImageLoad(context.Background(), input, true) |
|
| 34 | 34 |
if err != nil {
|
| 35 | 35 |
return err |
| 36 | 36 |
} |
| ... | ... |
@@ -4,6 +4,8 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"io" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
Cli "github.com/docker/docker/cli" |
| 8 | 10 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 11 |
"github.com/docker/docker/pkg/stdcopy" |
| ... | ... |
@@ -48,7 +50,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
|
| 48 | 48 |
Follow: *follow, |
| 49 | 49 |
Tail: *tail, |
| 50 | 50 |
} |
| 51 |
- responseBody, err := cli.client.ContainerLogs(options) |
|
| 51 |
+ responseBody, err := cli.client.ContainerLogs(context.Background(), options) |
|
| 52 | 52 |
if err != nil {
|
| 53 | 53 |
return err |
| 54 | 54 |
} |
| ... | ... |
@@ -4,6 +4,8 @@ import ( |
| 4 | 4 |
"errors" |
| 5 | 5 |
"fmt" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
Cli "github.com/docker/docker/cli" |
| 8 | 10 |
"github.com/docker/docker/pkg/jsonmessage" |
| 9 | 11 |
flag "github.com/docker/docker/pkg/mflag" |
| ... | ... |
@@ -77,7 +79,7 @@ func (cli *DockerCli) imagePullPrivileged(authConfig types.AuthConfig, imageID, |
| 77 | 77 |
RegistryAuth: encodedAuth, |
| 78 | 78 |
} |
| 79 | 79 |
|
| 80 |
- responseBody, err := cli.client.ImagePull(options, requestPrivilege) |
|
| 80 |
+ responseBody, err := cli.client.ImagePull(context.Background(), options, requestPrivilege) |
|
| 81 | 81 |
if err != nil {
|
| 82 | 82 |
return err |
| 83 | 83 |
} |
| ... | ... |
@@ -4,6 +4,8 @@ import ( |
| 4 | 4 |
"errors" |
| 5 | 5 |
"io" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
Cli "github.com/docker/docker/cli" |
| 8 | 10 |
"github.com/docker/docker/pkg/jsonmessage" |
| 9 | 11 |
flag "github.com/docker/docker/pkg/mflag" |
| ... | ... |
@@ -70,5 +72,5 @@ func (cli *DockerCli) imagePushPrivileged(authConfig types.AuthConfig, imageID, |
| 70 | 70 |
RegistryAuth: encodedAuth, |
| 71 | 71 |
} |
| 72 | 72 |
|
| 73 |
- return cli.client.ImagePush(options, requestPrivilege) |
|
| 73 |
+ return cli.client.ImagePush(context.Background(), options, requestPrivilege) |
|
| 74 | 74 |
} |
| ... | ... |
@@ -7,6 +7,8 @@ import ( |
| 7 | 7 |
"runtime" |
| 8 | 8 |
"strings" |
| 9 | 9 |
|
| 10 |
+ "golang.org/x/net/context" |
|
| 11 |
+ |
|
| 10 | 12 |
"github.com/Sirupsen/logrus" |
| 11 | 13 |
Cli "github.com/docker/docker/cli" |
| 12 | 14 |
derr "github.com/docker/docker/errors" |
| ... | ... |
@@ -269,7 +271,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
| 269 | 269 |
|
| 270 | 270 |
// Autoremove: wait for the container to finish, retrieve |
| 271 | 271 |
// the exit code and remove the container |
| 272 |
- if status, err = cli.client.ContainerWait(createResponse.ID); err != nil {
|
|
| 272 |
+ if status, err = cli.client.ContainerWait(context.Background(), createResponse.ID); err != nil {
|
|
| 273 | 273 |
return runStartContainerErr(err) |
| 274 | 274 |
} |
| 275 | 275 |
if _, status, err = getExitCode(cli, createResponse.ID); err != nil {
|
| ... | ... |
@@ -279,7 +281,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
| 279 | 279 |
// No Autoremove: Simply retrieve the exit code |
| 280 | 280 |
if !config.Tty {
|
| 281 | 281 |
// In non-TTY mode, we can't detach, so we must wait for container exit |
| 282 |
- if status, err = cli.client.ContainerWait(createResponse.ID); err != nil {
|
|
| 282 |
+ if status, err = cli.client.ContainerWait(context.Background(), createResponse.ID); err != nil {
|
|
| 283 | 283 |
return err |
| 284 | 284 |
} |
| 285 | 285 |
} else {
|
| ... | ... |
@@ -4,6 +4,8 @@ import ( |
| 4 | 4 |
"errors" |
| 5 | 5 |
"io" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
Cli "github.com/docker/docker/cli" |
| 8 | 10 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 11 |
) |
| ... | ... |
@@ -24,7 +26,7 @@ func (cli *DockerCli) CmdSave(args ...string) error {
|
| 24 | 24 |
return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
|
| 25 | 25 |
} |
| 26 | 26 |
|
| 27 |
- responseBody, err := cli.client.ImageSave(cmd.Args()) |
|
| 27 |
+ responseBody, err := cli.client.ImageSave(context.Background(), cmd.Args()) |
|
| 28 | 28 |
if err != nil {
|
| 29 | 29 |
return err |
| 30 | 30 |
} |
| ... | ... |
@@ -10,6 +10,8 @@ import ( |
| 10 | 10 |
"text/tabwriter" |
| 11 | 11 |
"time" |
| 12 | 12 |
|
| 13 |
+ "golang.org/x/net/context" |
|
| 14 |
+ |
|
| 13 | 15 |
Cli "github.com/docker/docker/cli" |
| 14 | 16 |
"github.com/docker/engine-api/types" |
| 15 | 17 |
"github.com/docker/engine-api/types/events" |
| ... | ... |
@@ -37,7 +39,7 @@ type stats struct {
|
| 37 | 37 |
} |
| 38 | 38 |
|
| 39 | 39 |
func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
|
| 40 |
- responseBody, err := cli.client.ContainerStats(s.Name, streamStats) |
|
| 40 |
+ responseBody, err := cli.client.ContainerStats(context.Background(), s.Name, streamStats) |
|
| 41 | 41 |
if err != nil {
|
| 42 | 42 |
s.mu.Lock() |
| 43 | 43 |
s.err = err |
| ... | ... |
@@ -195,7 +197,7 @@ func (cli *DockerCli) CmdStats(args ...string) error {
|
| 195 | 195 |
options := types.EventsOptions{
|
| 196 | 196 |
Filters: f, |
| 197 | 197 |
} |
| 198 |
- resBody, err := cli.client.Events(options) |
|
| 198 |
+ resBody, err := cli.client.Events(context.Background(), options) |
|
| 199 | 199 |
if err != nil {
|
| 200 | 200 |
c <- watch{err: err}
|
| 201 | 201 |
return |
| ... | ... |
@@ -4,6 +4,8 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"strings" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
Cli "github.com/docker/docker/cli" |
| 8 | 10 |
flag "github.com/docker/docker/pkg/mflag" |
| 9 | 11 |
) |
| ... | ... |
@@ -21,7 +23,7 @@ func (cli *DockerCli) CmdWait(args ...string) error {
|
| 21 | 21 |
|
| 22 | 22 |
var errs []string |
| 23 | 23 |
for _, name := range cmd.Args() {
|
| 24 |
- status, err := cli.client.ContainerWait(name) |
|
| 24 |
+ status, err := cli.client.ContainerWait(context.Background(), name) |
|
| 25 | 25 |
if err != nil {
|
| 26 | 26 |
errs = append(errs, err.Error()) |
| 27 | 27 |
} else {
|
| ... | ... |
@@ -7,7 +7,7 @@ source 'hack/.vendor-helpers.sh' |
| 7 | 7 |
|
| 8 | 8 |
# the following lines are in sorted order, FYI |
| 9 | 9 |
clone git github.com/Azure/go-ansiterm 70b2c90b260171e829f1ebd7c17f600c11858dbe |
| 10 |
-clone git github.com/Microsoft/go-winio 2b085935f02c272e7a1855df6f8fe03029ffcadd |
|
| 10 |
+clone git github.com/Microsoft/go-winio eb176a9831c54b88eaf9eb4fbc24b94080d910ad |
|
| 11 | 11 |
clone git github.com/Sirupsen/logrus v0.9.0 # logrus is a common dependency among multiple deps |
| 12 | 12 |
clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a |
| 13 | 13 |
clone git github.com/go-check/check 11d3bc7aa68e238947792f30573146a3231fc0f1 |
| ... | ... |
@@ -23,8 +23,8 @@ clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b |
| 23 | 23 |
clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://github.com/golang/net.git |
| 24 | 24 |
clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git |
| 25 | 25 |
clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3 |
| 26 |
-clone git github.com/docker/go-connections v0.1.2 |
|
| 27 |
-clone git github.com/docker/engine-api bdbab71ec21209ef56dffdbe42c9d21843c30862 |
|
| 26 |
+clone git github.com/docker/go-connections v0.1.3 |
|
| 27 |
+clone git github.com/docker/engine-api 9a940e4ead265e18d4feb9e3c515428966a08278 |
|
| 28 | 28 |
clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de |
| 29 | 29 |
clone git github.com/imdario/mergo 0.2.1 |
| 30 | 30 |
|
| ... | ... |
@@ -194,7 +194,7 @@ func (d *Daemon) getClientConfig() (*clientConfig, error) {
|
| 194 | 194 |
transport = &http.Transport{}
|
| 195 | 195 |
} |
| 196 | 196 |
|
| 197 |
- sockets.ConfigureTCPTransport(transport, proto, addr) |
|
| 197 |
+ sockets.ConfigureTransport(transport, proto, addr) |
|
| 198 | 198 |
|
| 199 | 199 |
return &clientConfig{
|
| 200 | 200 |
transport: transport, |
| ... | ... |
@@ -30,7 +30,7 @@ func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) {
|
| 30 | 30 |
tr.TLSClientConfig = c |
| 31 | 31 |
|
| 32 | 32 |
protoAndAddr := strings.Split(addr, "://") |
| 33 |
- sockets.ConfigureTCPTransport(tr, protoAndAddr[0], protoAndAddr[1]) |
|
| 33 |
+ sockets.ConfigureTransport(tr, protoAndAddr[0], protoAndAddr[1]) |
|
| 34 | 34 |
|
| 35 | 35 |
scheme := protoAndAddr[0] |
| 36 | 36 |
if scheme != "https" {
|
| ... | ... |
@@ -65,7 +65,7 @@ func LookupSidByName(name string) (sid string, err error) {
|
| 65 | 65 |
if err != nil {
|
| 66 | 66 |
return "", &AccountLookupError{name, err}
|
| 67 | 67 |
} |
| 68 |
- sid = syscall.UTF16ToString((*[1 << 30]uint16)(unsafe.Pointer(strBuffer))[:]) |
|
| 68 |
+ sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:]) |
|
| 69 | 69 |
localFree(uintptr(unsafe.Pointer(strBuffer))) |
| 70 | 70 |
return sid, nil |
| 71 | 71 |
} |
| ... | ... |
@@ -1,16 +1,14 @@ |
| 1 | 1 |
package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "crypto/tls" |
|
| 5 | 4 |
"fmt" |
| 6 |
- "net" |
|
| 7 | 5 |
"net/http" |
| 8 | 6 |
"net/url" |
| 9 | 7 |
"os" |
| 10 | 8 |
"path/filepath" |
| 11 | 9 |
"strings" |
| 12 |
- "time" |
|
| 13 | 10 |
|
| 11 |
+ "github.com/docker/engine-api/client/transport" |
|
| 14 | 12 |
"github.com/docker/go-connections/tlsconfig" |
| 15 | 13 |
) |
| 16 | 14 |
|
| ... | ... |
@@ -21,17 +19,13 @@ type Client struct {
|
| 21 | 21 |
proto string |
| 22 | 22 |
// addr holds the client address. |
| 23 | 23 |
addr string |
| 24 |
- // basePath holds the path to prepend to the requests |
|
| 24 |
+ // basePath holds the path to prepend to the requests. |
|
| 25 | 25 |
basePath string |
| 26 |
- // scheme holds the scheme of the client i.e. https. |
|
| 27 |
- scheme string |
|
| 28 |
- // tlsConfig holds the tls configuration to use in hijacked requests. |
|
| 29 |
- tlsConfig *tls.Config |
|
| 30 |
- // httpClient holds the client transport instance. Exported to keep the old code running. |
|
| 31 |
- httpClient *http.Client |
|
| 26 |
+ // transport is the interface to sends request with, it implements transport.Client. |
|
| 27 |
+ transport transport.Client |
|
| 32 | 28 |
// version of the server to talk to. |
| 33 | 29 |
version string |
| 34 |
- // custom http headers configured by users |
|
| 30 |
+ // custom http headers configured by users. |
|
| 35 | 31 |
customHTTPHeaders map[string]string |
| 36 | 32 |
} |
| 37 | 33 |
|
| ... | ... |
@@ -41,7 +35,7 @@ type Client struct {
|
| 41 | 41 |
// Use DOCKER_CERT_PATH to load the tls certificates from. |
| 42 | 42 |
// Use DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default. |
| 43 | 43 |
func NewEnvClient() (*Client, error) {
|
| 44 |
- var transport *http.Transport |
|
| 44 |
+ var client *http.Client |
|
| 45 | 45 |
if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" {
|
| 46 | 46 |
options := tlsconfig.Options{
|
| 47 | 47 |
CAFile: filepath.Join(dockerCertPath, "ca.pem"), |
| ... | ... |
@@ -54,8 +48,10 @@ func NewEnvClient() (*Client, error) {
|
| 54 | 54 |
return nil, err |
| 55 | 55 |
} |
| 56 | 56 |
|
| 57 |
- transport = &http.Transport{
|
|
| 58 |
- TLSClientConfig: tlsc, |
|
| 57 |
+ client = &http.Client{
|
|
| 58 |
+ Transport: &http.Transport{
|
|
| 59 |
+ TLSClientConfig: tlsc, |
|
| 60 |
+ }, |
|
| 59 | 61 |
} |
| 60 | 62 |
} |
| 61 | 63 |
|
| ... | ... |
@@ -63,42 +59,29 @@ func NewEnvClient() (*Client, error) {
|
| 63 | 63 |
if host == "" {
|
| 64 | 64 |
host = DefaultDockerHost |
| 65 | 65 |
} |
| 66 |
- return NewClient(host, os.Getenv("DOCKER_API_VERSION"), transport, nil)
|
|
| 66 |
+ return NewClient(host, os.Getenv("DOCKER_API_VERSION"), client, nil)
|
|
| 67 | 67 |
} |
| 68 | 68 |
|
| 69 | 69 |
// NewClient initializes a new API client for the given host and API version. |
| 70 | 70 |
// It won't send any version information if the version number is empty. |
| 71 |
-// It uses the transport to create a new http client. |
|
| 71 |
+// It uses the given http client as transport. |
|
| 72 | 72 |
// It also initializes the custom http headers to add to each request. |
| 73 |
-func NewClient(host string, version string, transport *http.Transport, httpHeaders map[string]string) (*Client, error) {
|
|
| 74 |
- var ( |
|
| 75 |
- basePath string |
|
| 76 |
- scheme = "http" |
|
| 77 |
- protoAddrParts = strings.SplitN(host, "://", 2) |
|
| 78 |
- proto, addr = protoAddrParts[0], protoAddrParts[1] |
|
| 79 |
- ) |
|
| 80 |
- |
|
| 81 |
- if proto == "tcp" {
|
|
| 82 |
- parsed, err := url.Parse("tcp://" + addr)
|
|
| 83 |
- if err != nil {
|
|
| 84 |
- return nil, err |
|
| 85 |
- } |
|
| 86 |
- addr = parsed.Host |
|
| 87 |
- basePath = parsed.Path |
|
| 73 |
+func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) {
|
|
| 74 |
+ proto, addr, basePath, err := ParseHost(host) |
|
| 75 |
+ if err != nil {
|
|
| 76 |
+ return nil, err |
|
| 88 | 77 |
} |
| 89 | 78 |
|
| 90 |
- transport = configureTransport(transport, proto, addr) |
|
| 91 |
- if transport.TLSClientConfig != nil {
|
|
| 92 |
- scheme = "https" |
|
| 79 |
+ transport, err := transport.NewTransportWithHTTP(proto, addr, client) |
|
| 80 |
+ if err != nil {
|
|
| 81 |
+ return nil, err |
|
| 93 | 82 |
} |
| 94 | 83 |
|
| 95 | 84 |
return &Client{
|
| 96 | 85 |
proto: proto, |
| 97 | 86 |
addr: addr, |
| 98 | 87 |
basePath: basePath, |
| 99 |
- scheme: scheme, |
|
| 100 |
- tlsConfig: transport.TLSClientConfig, |
|
| 101 |
- httpClient: &http.Client{Transport: transport},
|
|
| 88 |
+ transport: transport, |
|
| 102 | 89 |
version: version, |
| 103 | 90 |
customHTTPHeaders: httpHeaders, |
| 104 | 91 |
}, nil |
| ... | ... |
@@ -127,23 +110,22 @@ func (cli *Client) ClientVersion() string {
|
| 127 | 127 |
return cli.version |
| 128 | 128 |
} |
| 129 | 129 |
|
| 130 |
-func configureTransport(tr *http.Transport, proto, addr string) *http.Transport {
|
|
| 131 |
- if tr == nil {
|
|
| 132 |
- tr = &http.Transport{}
|
|
| 130 |
+// ParseHost verifies that the given host strings is valid. |
|
| 131 |
+func ParseHost(host string) (string, string, string, error) {
|
|
| 132 |
+ protoAddrParts := strings.SplitN(host, "://", 2) |
|
| 133 |
+ if len(protoAddrParts) == 1 {
|
|
| 134 |
+ return "", "", "", fmt.Errorf("unable to parse docker host `%s`", host)
|
|
| 133 | 135 |
} |
| 134 | 136 |
|
| 135 |
- // Why 32? See https://github.com/docker/docker/pull/8035. |
|
| 136 |
- timeout := 32 * time.Second |
|
| 137 |
- if proto == "unix" {
|
|
| 138 |
- // No need for compression in local communications. |
|
| 139 |
- tr.DisableCompression = true |
|
| 140 |
- tr.Dial = func(_, _ string) (net.Conn, error) {
|
|
| 141 |
- return net.DialTimeout(proto, addr, timeout) |
|
| 137 |
+ var basePath string |
|
| 138 |
+ proto, addr := protoAddrParts[0], protoAddrParts[1] |
|
| 139 |
+ if proto == "tcp" {
|
|
| 140 |
+ parsed, err := url.Parse("tcp://" + addr)
|
|
| 141 |
+ if err != nil {
|
|
| 142 |
+ return "", "", "", err |
|
| 142 | 143 |
} |
| 143 |
- } else {
|
|
| 144 |
- tr.Proxy = http.ProxyFromEnvironment |
|
| 145 |
- tr.Dial = (&net.Dialer{Timeout: timeout}).Dial
|
|
| 144 |
+ addr = parsed.Host |
|
| 145 |
+ basePath = parsed.Path |
|
| 146 | 146 |
} |
| 147 |
- |
|
| 148 |
- return tr |
|
| 147 |
+ return proto, addr, basePath, nil |
|
| 149 | 148 |
} |
| ... | ... |
@@ -3,18 +3,20 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
"net/url" |
| 6 |
+ |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 6 | 8 |
) |
| 7 | 9 |
|
| 8 | 10 |
// ContainerStats returns near realtime stats for a given container. |
| 9 | 11 |
// It's up to the caller to close the io.ReadCloser returned. |
| 10 |
-func (cli *Client) ContainerStats(containerID string, stream bool) (io.ReadCloser, error) {
|
|
| 12 |
+func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (io.ReadCloser, error) {
|
|
| 11 | 13 |
query := url.Values{}
|
| 12 | 14 |
query.Set("stream", "0")
|
| 13 | 15 |
if stream {
|
| 14 | 16 |
query.Set("stream", "1")
|
| 15 | 17 |
} |
| 16 | 18 |
|
| 17 |
- resp, err := cli.get("/containers/"+containerID+"/stats", query, nil)
|
|
| 19 |
+ resp, err := cli.getWithContext(ctx, "/containers/"+containerID+"/stats", query, nil) |
|
| 18 | 20 |
if err != nil {
|
| 19 | 21 |
return nil, err |
| 20 | 22 |
} |
| ... | ... |
@@ -10,6 +10,8 @@ import ( |
| 10 | 10 |
"path/filepath" |
| 11 | 11 |
"strings" |
| 12 | 12 |
|
| 13 |
+ "golang.org/x/net/context" |
|
| 14 |
+ |
|
| 13 | 15 |
"github.com/docker/engine-api/types" |
| 14 | 16 |
) |
| 15 | 17 |
|
| ... | ... |
@@ -28,7 +30,7 @@ func (cli *Client) ContainerStatPath(containerID, path string) (types.ContainerP |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 | 30 |
// CopyToContainer copies content into the container filesystem. |
| 31 |
-func (cli *Client) CopyToContainer(options types.CopyToContainerOptions) error {
|
|
| 31 |
+func (cli *Client) CopyToContainer(ctx context.Context, options types.CopyToContainerOptions) error {
|
|
| 32 | 32 |
query := url.Values{}
|
| 33 | 33 |
query.Set("path", filepath.ToSlash(options.Path)) // Normalize the paths used in the API.
|
| 34 | 34 |
// 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 {
|
| 38 | 38 |
|
| 39 | 39 |
path := fmt.Sprintf("/containers/%s/archive", options.ContainerID)
|
| 40 | 40 |
|
| 41 |
- response, err := cli.putRaw(path, query, options.Content, nil) |
|
| 41 |
+ response, err := cli.putRawWithContext(ctx, path, query, options.Content, nil) |
|
| 42 | 42 |
if err != nil {
|
| 43 | 43 |
return err |
| 44 | 44 |
} |
| ... | ... |
@@ -53,12 +55,12 @@ func (cli *Client) CopyToContainer(options types.CopyToContainerOptions) error {
|
| 53 | 53 |
|
| 54 | 54 |
// CopyFromContainer get the content from the container and return it as a Reader |
| 55 | 55 |
// to manipulate it in the host. It's up to the caller to close the reader. |
| 56 |
-func (cli *Client) CopyFromContainer(containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
|
|
| 56 |
+func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
|
|
| 57 | 57 |
query := make(url.Values, 1) |
| 58 | 58 |
query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API.
|
| 59 | 59 |
|
| 60 | 60 |
apiPath := fmt.Sprintf("/containers/%s/archive", containerID)
|
| 61 |
- response, err := cli.get(apiPath, query, nil) |
|
| 61 |
+ response, err := cli.getWithContext(ctx, apiPath, query, nil) |
|
| 62 | 62 |
if err != nil {
|
| 63 | 63 |
return nil, types.ContainerPathStat{}, err
|
| 64 | 64 |
} |
| ... | ... |
@@ -5,6 +5,8 @@ import ( |
| 5 | 5 |
"net/url" |
| 6 | 6 |
"time" |
| 7 | 7 |
|
| 8 |
+ "golang.org/x/net/context" |
|
| 9 |
+ |
|
| 8 | 10 |
"github.com/docker/engine-api/types" |
| 9 | 11 |
"github.com/docker/engine-api/types/filters" |
| 10 | 12 |
timetypes "github.com/docker/engine-api/types/time" |
| ... | ... |
@@ -12,7 +14,7 @@ import ( |
| 12 | 12 |
|
| 13 | 13 |
// Events returns a stream of events in the daemon in a ReadCloser. |
| 14 | 14 |
// It's up to the caller to close the stream. |
| 15 |
-func (cli *Client) Events(options types.EventsOptions) (io.ReadCloser, error) {
|
|
| 15 |
+func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (io.ReadCloser, error) {
|
|
| 16 | 16 |
query := url.Values{}
|
| 17 | 17 |
ref := time.Now() |
| 18 | 18 |
|
| ... | ... |
@@ -38,7 +40,7 @@ func (cli *Client) Events(options types.EventsOptions) (io.ReadCloser, error) {
|
| 38 | 38 |
query.Set("filters", filterJSON)
|
| 39 | 39 |
} |
| 40 | 40 |
|
| 41 |
- serverResponse, err := cli.get("/events", query, nil)
|
|
| 41 |
+ serverResponse, err := cli.getWithContext(ctx, "/events", query, nil) |
|
| 42 | 42 |
if err != nil {
|
| 43 | 43 |
return nil, err |
| 44 | 44 |
} |
| ... | ... |
@@ -3,13 +3,15 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
"net/url" |
| 6 |
+ |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 6 | 8 |
) |
| 7 | 9 |
|
| 8 | 10 |
// ContainerExport retrieves the raw contents of a container |
| 9 | 11 |
// and returns them as a io.ReadCloser. It's up to the caller |
| 10 | 12 |
// to close the stream. |
| 11 |
-func (cli *Client) ContainerExport(containerID string) (io.ReadCloser, error) {
|
|
| 12 |
- serverResp, err := cli.get("/containers/"+containerID+"/export", url.Values{}, nil)
|
|
| 13 |
+func (cli *Client) ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) {
|
|
| 14 |
+ serverResp, err := cli.getWithContext(ctx, "/containers/"+containerID+"/export", url.Values{}, nil)
|
|
| 13 | 15 |
if err != nil {
|
| 14 | 16 |
return nil, err |
| 15 | 17 |
} |
| ... | ... |
@@ -11,6 +11,7 @@ import ( |
| 11 | 11 |
"time" |
| 12 | 12 |
|
| 13 | 13 |
"github.com/docker/engine-api/types" |
| 14 |
+ "github.com/docker/go-connections/sockets" |
|
| 14 | 15 |
) |
| 15 | 16 |
|
| 16 | 17 |
// tlsClientCon holds tls information and a dialed connection. |
| ... | ... |
@@ -44,7 +45,7 @@ func (cli *Client) postHijacked(path string, query url.Values, body interface{},
|
| 44 | 44 |
req.Header.Set("Connection", "Upgrade")
|
| 45 | 45 |
req.Header.Set("Upgrade", "tcp")
|
| 46 | 46 |
|
| 47 |
- conn, err := dial(cli.proto, cli.addr, cli.tlsConfig) |
|
| 47 |
+ conn, err := dial(cli.proto, cli.addr, cli.transport.TLSConfig()) |
|
| 48 | 48 |
if err != nil {
|
| 49 | 49 |
if strings.Contains(err.Error(), "connection refused") {
|
| 50 | 50 |
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 |
| 156 | 156 |
} |
| 157 | 157 |
|
| 158 | 158 |
func dial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {
|
| 159 |
- if tlsConfig != nil && proto != "unix" {
|
|
| 159 |
+ if tlsConfig != nil && proto != "unix" && proto != "npipe" {
|
|
| 160 | 160 |
// Notice this isn't Go standard's tls.Dial function |
| 161 | 161 |
return tlsDial(proto, addr, tlsConfig) |
| 162 | 162 |
} |
| 163 |
+ if proto == "npipe" {
|
|
| 164 |
+ return sockets.DialPipe(addr, 32*time.Second) |
|
| 165 |
+ } |
|
| 163 | 166 |
return net.Dial(proto, addr) |
| 164 | 167 |
} |
| ... | ... |
@@ -9,6 +9,8 @@ import ( |
| 9 | 9 |
"strconv" |
| 10 | 10 |
"strings" |
| 11 | 11 |
|
| 12 |
+ "golang.org/x/net/context" |
|
| 13 |
+ |
|
| 12 | 14 |
"github.com/docker/engine-api/types" |
| 13 | 15 |
"github.com/docker/engine-api/types/container" |
| 14 | 16 |
) |
| ... | ... |
@@ -18,7 +20,7 @@ var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`) |
| 18 | 18 |
// ImageBuild sends request to the daemon to build images. |
| 19 | 19 |
// The Body in the response implement an io.ReadCloser and it's up to the caller to |
| 20 | 20 |
// close it. |
| 21 |
-func (cli *Client) ImageBuild(options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
|
| 21 |
+func (cli *Client) ImageBuild(ctx context.Context, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
|
|
| 22 | 22 |
query, err := imageBuildOptionsToQuery(options) |
| 23 | 23 |
if err != nil {
|
| 24 | 24 |
return types.ImageBuildResponse{}, err
|
| ... | ... |
@@ -32,7 +34,7 @@ func (cli *Client) ImageBuild(options types.ImageBuildOptions) (types.ImageBuild |
| 32 | 32 |
headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
|
| 33 | 33 |
headers.Set("Content-Type", "application/tar")
|
| 34 | 34 |
|
| 35 |
- serverResp, err := cli.postRaw("/build", query, options.Context, headers)
|
|
| 35 |
+ serverResp, err := cli.postRaw(ctx, "/build", query, options.Context, headers) |
|
| 36 | 36 |
if err != nil {
|
| 37 | 37 |
return types.ImageBuildResponse{}, err
|
| 38 | 38 |
} |
| ... | ... |
@@ -4,23 +4,25 @@ import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
"net/url" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
"github.com/docker/engine-api/types" |
| 8 | 10 |
) |
| 9 | 11 |
|
| 10 | 12 |
// ImageCreate creates a new image based in the parent options. |
| 11 | 13 |
// It returns the JSON content in the response body. |
| 12 |
-func (cli *Client) ImageCreate(options types.ImageCreateOptions) (io.ReadCloser, error) {
|
|
| 14 |
+func (cli *Client) ImageCreate(ctx context.Context, options types.ImageCreateOptions) (io.ReadCloser, error) {
|
|
| 13 | 15 |
query := url.Values{}
|
| 14 | 16 |
query.Set("fromImage", options.Parent)
|
| 15 | 17 |
query.Set("tag", options.Tag)
|
| 16 |
- resp, err := cli.tryImageCreate(query, options.RegistryAuth) |
|
| 18 |
+ resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) |
|
| 17 | 19 |
if err != nil {
|
| 18 | 20 |
return nil, err |
| 19 | 21 |
} |
| 20 | 22 |
return resp.body, nil |
| 21 | 23 |
} |
| 22 | 24 |
|
| 23 |
-func (cli *Client) tryImageCreate(query url.Values, registryAuth string) (*serverResponse, error) {
|
|
| 25 |
+func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (*serverResponse, error) {
|
|
| 24 | 26 |
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
|
| 25 |
- return cli.post("/images/create", query, nil, headers)
|
|
| 27 |
+ return cli.postWithContext(ctx, "/images/create", query, nil, headers) |
|
| 26 | 28 |
} |
| ... | ... |
@@ -4,12 +4,14 @@ import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
"net/url" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
"github.com/docker/engine-api/types" |
| 8 | 10 |
) |
| 9 | 11 |
|
| 10 | 12 |
// ImageImport creates a new image based in the source options. |
| 11 | 13 |
// It returns the JSON content in the response body. |
| 12 |
-func (cli *Client) ImageImport(options types.ImageImportOptions) (io.ReadCloser, error) {
|
|
| 14 |
+func (cli *Client) ImageImport(ctx context.Context, options types.ImageImportOptions) (io.ReadCloser, error) {
|
|
| 13 | 15 |
query := url.Values{}
|
| 14 | 16 |
query.Set("fromSrc", options.SourceName)
|
| 15 | 17 |
query.Set("repo", options.RepositoryName)
|
| ... | ... |
@@ -19,7 +21,7 @@ func (cli *Client) ImageImport(options types.ImageImportOptions) (io.ReadCloser, |
| 19 | 19 |
query.Add("changes", change)
|
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 |
- resp, err := cli.postRaw("/images/create", query, options.Source, nil)
|
|
| 22 |
+ resp, err := cli.postRaw(ctx, "/images/create", query, options.Source, nil) |
|
| 23 | 23 |
if err != nil {
|
| 24 | 24 |
return nil, err |
| 25 | 25 |
} |
| ... | ... |
@@ -4,14 +4,21 @@ import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
"net/url" |
| 6 | 6 |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 7 | 9 |
"github.com/docker/engine-api/types" |
| 8 | 10 |
) |
| 9 | 11 |
|
| 10 | 12 |
// ImageLoad loads an image in the docker host from the client host. |
| 11 | 13 |
// It's up to the caller to close the io.ReadCloser returned by |
| 12 | 14 |
// this function. |
| 13 |
-func (cli *Client) ImageLoad(input io.Reader) (types.ImageLoadResponse, error) {
|
|
| 14 |
- resp, err := cli.postRaw("/images/load", url.Values{}, input, nil)
|
|
| 15 |
+func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) {
|
|
| 16 |
+ v := url.Values{}
|
|
| 17 |
+ v.Set("quiet", "0")
|
|
| 18 |
+ if quiet {
|
|
| 19 |
+ v.Set("quiet", "1")
|
|
| 20 |
+ } |
|
| 21 |
+ resp, err := cli.postRaw(ctx, "/images/load", v, input, nil) |
|
| 15 | 22 |
if err != nil {
|
| 16 | 23 |
return types.ImageLoadResponse{}, err
|
| 17 | 24 |
} |
| ... | ... |
@@ -5,6 +5,8 @@ import ( |
| 5 | 5 |
"net/http" |
| 6 | 6 |
"net/url" |
| 7 | 7 |
|
| 8 |
+ "golang.org/x/net/context" |
|
| 9 |
+ |
|
| 8 | 10 |
"github.com/docker/engine-api/types" |
| 9 | 11 |
) |
| 10 | 12 |
|
| ... | ... |
@@ -12,20 +14,20 @@ import ( |
| 12 | 12 |
// It executes the privileged function if the operation is unauthorized |
| 13 | 13 |
// and it tries one more time. |
| 14 | 14 |
// It's up to the caller to handle the io.ReadCloser and close it properly. |
| 15 |
-func (cli *Client) ImagePull(options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) {
|
|
| 15 |
+func (cli *Client) ImagePull(ctx context.Context, options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) {
|
|
| 16 | 16 |
query := url.Values{}
|
| 17 | 17 |
query.Set("fromImage", options.ImageID)
|
| 18 | 18 |
if options.Tag != "" {
|
| 19 | 19 |
query.Set("tag", options.Tag)
|
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 |
- resp, err := cli.tryImageCreate(query, options.RegistryAuth) |
|
| 22 |
+ resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) |
|
| 23 | 23 |
if resp.statusCode == http.StatusUnauthorized {
|
| 24 | 24 |
newAuthHeader, privilegeErr := privilegeFunc() |
| 25 | 25 |
if privilegeErr != nil {
|
| 26 | 26 |
return nil, privilegeErr |
| 27 | 27 |
} |
| 28 |
- resp, err = cli.tryImageCreate(query, newAuthHeader) |
|
| 28 |
+ resp, err = cli.tryImageCreate(ctx, query, newAuthHeader) |
|
| 29 | 29 |
} |
| 30 | 30 |
if err != nil {
|
| 31 | 31 |
return nil, err |
| ... | ... |
@@ -5,6 +5,8 @@ import ( |
| 5 | 5 |
"net/http" |
| 6 | 6 |
"net/url" |
| 7 | 7 |
|
| 8 |
+ "golang.org/x/net/context" |
|
| 9 |
+ |
|
| 8 | 10 |
"github.com/docker/engine-api/types" |
| 9 | 11 |
) |
| 10 | 12 |
|
| ... | ... |
@@ -12,17 +14,17 @@ import ( |
| 12 | 12 |
// It executes the privileged function if the operation is unauthorized |
| 13 | 13 |
// and it tries one more time. |
| 14 | 14 |
// It's up to the caller to handle the io.ReadCloser and close it properly. |
| 15 |
-func (cli *Client) ImagePush(options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) {
|
|
| 15 |
+func (cli *Client) ImagePush(ctx context.Context, options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) {
|
|
| 16 | 16 |
query := url.Values{}
|
| 17 | 17 |
query.Set("tag", options.Tag)
|
| 18 | 18 |
|
| 19 |
- resp, err := cli.tryImagePush(options.ImageID, query, options.RegistryAuth) |
|
| 19 |
+ resp, err := cli.tryImagePush(ctx, options.ImageID, query, options.RegistryAuth) |
|
| 20 | 20 |
if resp.statusCode == http.StatusUnauthorized {
|
| 21 | 21 |
newAuthHeader, privilegeErr := privilegeFunc() |
| 22 | 22 |
if privilegeErr != nil {
|
| 23 | 23 |
return nil, privilegeErr |
| 24 | 24 |
} |
| 25 |
- resp, err = cli.tryImagePush(options.ImageID, query, newAuthHeader) |
|
| 25 |
+ resp, err = cli.tryImagePush(ctx, options.ImageID, query, newAuthHeader) |
|
| 26 | 26 |
} |
| 27 | 27 |
if err != nil {
|
| 28 | 28 |
return nil, err |
| ... | ... |
@@ -30,7 +32,7 @@ func (cli *Client) ImagePush(options types.ImagePushOptions, privilegeFunc Reque |
| 30 | 30 |
return resp.body, nil |
| 31 | 31 |
} |
| 32 | 32 |
|
| 33 |
-func (cli *Client) tryImagePush(imageID string, query url.Values, registryAuth string) (*serverResponse, error) {
|
|
| 33 |
+func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, registryAuth string) (*serverResponse, error) {
|
|
| 34 | 34 |
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
|
| 35 |
- return cli.post("/images/"+imageID+"/push", query, nil, headers)
|
|
| 35 |
+ return cli.postWithContext(ctx, "/images/"+imageID+"/push", query, nil, headers) |
|
| 36 | 36 |
} |
| ... | ... |
@@ -3,16 +3,18 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
"net/url" |
| 6 |
+ |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 6 | 8 |
) |
| 7 | 9 |
|
| 8 | 10 |
// ImageSave retrieves one or more images from the docker host as a io.ReadCloser. |
| 9 | 11 |
// It's up to the caller to store the images and close the stream. |
| 10 |
-func (cli *Client) ImageSave(imageIDs []string) (io.ReadCloser, error) {
|
|
| 12 |
+func (cli *Client) ImageSave(ctx context.Context, imageIDs []string) (io.ReadCloser, error) {
|
|
| 11 | 13 |
query := url.Values{
|
| 12 | 14 |
"names": imageIDs, |
| 13 | 15 |
} |
| 14 | 16 |
|
| 15 |
- resp, err := cli.get("/images/get", query, nil)
|
|
| 17 |
+ resp, err := cli.getWithContext(ctx, "/images/get", query, nil) |
|
| 16 | 18 |
if err != nil {
|
| 17 | 19 |
return nil, err |
| 18 | 20 |
} |
| ... | ... |
@@ -3,6 +3,8 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"io" |
| 5 | 5 |
|
| 6 |
+ "golang.org/x/net/context" |
|
| 7 |
+ |
|
| 6 | 8 |
"github.com/docker/engine-api/types" |
| 7 | 9 |
"github.com/docker/engine-api/types/container" |
| 8 | 10 |
"github.com/docker/engine-api/types/filters" |
| ... | ... |
@@ -22,40 +24,40 @@ type APIClient interface {
|
| 22 | 22 |
ContainerExecInspect(execID string) (types.ContainerExecInspect, error) |
| 23 | 23 |
ContainerExecResize(options types.ResizeOptions) error |
| 24 | 24 |
ContainerExecStart(execID string, config types.ExecStartCheck) error |
| 25 |
- ContainerExport(containerID string) (io.ReadCloser, error) |
|
| 25 |
+ ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) |
|
| 26 | 26 |
ContainerInspect(containerID string) (types.ContainerJSON, error) |
| 27 | 27 |
ContainerInspectWithRaw(containerID string, getSize bool) (types.ContainerJSON, []byte, error) |
| 28 | 28 |
ContainerKill(containerID, signal string) error |
| 29 | 29 |
ContainerList(options types.ContainerListOptions) ([]types.Container, error) |
| 30 |
- ContainerLogs(options types.ContainerLogsOptions) (io.ReadCloser, error) |
|
| 30 |
+ ContainerLogs(ctx context.Context, options types.ContainerLogsOptions) (io.ReadCloser, error) |
|
| 31 | 31 |
ContainerPause(containerID string) error |
| 32 | 32 |
ContainerRemove(options types.ContainerRemoveOptions) error |
| 33 | 33 |
ContainerRename(containerID, newContainerName string) error |
| 34 | 34 |
ContainerResize(options types.ResizeOptions) error |
| 35 | 35 |
ContainerRestart(containerID string, timeout int) error |
| 36 | 36 |
ContainerStatPath(containerID, path string) (types.ContainerPathStat, error) |
| 37 |
- ContainerStats(containerID string, stream bool) (io.ReadCloser, error) |
|
| 37 |
+ ContainerStats(ctx context.Context, containerID string, stream bool) (io.ReadCloser, error) |
|
| 38 | 38 |
ContainerStart(containerID string) error |
| 39 | 39 |
ContainerStop(containerID string, timeout int) error |
| 40 | 40 |
ContainerTop(containerID string, arguments []string) (types.ContainerProcessList, error) |
| 41 | 41 |
ContainerUnpause(containerID string) error |
| 42 | 42 |
ContainerUpdate(containerID string, updateConfig container.UpdateConfig) error |
| 43 |
- ContainerWait(containerID string) (int, error) |
|
| 44 |
- CopyFromContainer(containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) |
|
| 45 |
- CopyToContainer(options types.CopyToContainerOptions) error |
|
| 46 |
- Events(options types.EventsOptions) (io.ReadCloser, error) |
|
| 47 |
- ImageBuild(options types.ImageBuildOptions) (types.ImageBuildResponse, error) |
|
| 48 |
- ImageCreate(options types.ImageCreateOptions) (io.ReadCloser, error) |
|
| 43 |
+ ContainerWait(ctx context.Context, containerID string) (int, error) |
|
| 44 |
+ CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) |
|
| 45 |
+ CopyToContainer(ctx context.Context, options types.CopyToContainerOptions) error |
|
| 46 |
+ Events(ctx context.Context, options types.EventsOptions) (io.ReadCloser, error) |
|
| 47 |
+ ImageBuild(ctx context.Context, options types.ImageBuildOptions) (types.ImageBuildResponse, error) |
|
| 48 |
+ ImageCreate(ctx context.Context, options types.ImageCreateOptions) (io.ReadCloser, error) |
|
| 49 | 49 |
ImageHistory(imageID string) ([]types.ImageHistory, error) |
| 50 |
- ImageImport(options types.ImageImportOptions) (io.ReadCloser, error) |
|
| 50 |
+ ImageImport(ctx context.Context, options types.ImageImportOptions) (io.ReadCloser, error) |
|
| 51 | 51 |
ImageInspectWithRaw(imageID string, getSize bool) (types.ImageInspect, []byte, error) |
| 52 | 52 |
ImageList(options types.ImageListOptions) ([]types.Image, error) |
| 53 |
- ImageLoad(input io.Reader) (types.ImageLoadResponse, error) |
|
| 54 |
- ImagePull(options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) |
|
| 55 |
- ImagePush(options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) |
|
| 53 |
+ ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) |
|
| 54 |
+ ImagePull(ctx context.Context, options types.ImagePullOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) |
|
| 55 |
+ ImagePush(ctx context.Context, options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) |
|
| 56 | 56 |
ImageRemove(options types.ImageRemoveOptions) ([]types.ImageDelete, error) |
| 57 | 57 |
ImageSearch(options types.ImageSearchOptions, privilegeFunc RequestPrivilegeFunc) ([]registry.SearchResult, error) |
| 58 |
- ImageSave(imageIDs []string) (io.ReadCloser, error) |
|
| 58 |
+ ImageSave(ctx context.Context, imageIDs []string) (io.ReadCloser, error) |
|
| 59 | 59 |
ImageTag(options types.ImageTagOptions) error |
| 60 | 60 |
Info() (types.Info, error) |
| 61 | 61 |
NetworkConnect(networkID, containerID string, config *network.EndpointSettings) error |
| ... | ... |
@@ -5,13 +5,15 @@ import ( |
| 5 | 5 |
"net/url" |
| 6 | 6 |
"time" |
| 7 | 7 |
|
| 8 |
+ "golang.org/x/net/context" |
|
| 9 |
+ |
|
| 8 | 10 |
"github.com/docker/engine-api/types" |
| 9 | 11 |
timetypes "github.com/docker/engine-api/types/time" |
| 10 | 12 |
) |
| 11 | 13 |
|
| 12 | 14 |
// ContainerLogs returns the logs generated by a container in an io.ReadCloser. |
| 13 | 15 |
// It's up to the caller to close the stream. |
| 14 |
-func (cli *Client) ContainerLogs(options types.ContainerLogsOptions) (io.ReadCloser, error) {
|
|
| 16 |
+func (cli *Client) ContainerLogs(ctx context.Context, options types.ContainerLogsOptions) (io.ReadCloser, error) {
|
|
| 15 | 17 |
query := url.Values{}
|
| 16 | 18 |
if options.ShowStdout {
|
| 17 | 19 |
query.Set("stdout", "1")
|
| ... | ... |
@@ -38,7 +40,7 @@ func (cli *Client) ContainerLogs(options types.ContainerLogsOptions) (io.ReadClo |
| 38 | 38 |
} |
| 39 | 39 |
query.Set("tail", options.Tail)
|
| 40 | 40 |
|
| 41 |
- resp, err := cli.get("/containers/"+options.ContainerID+"/logs", query, nil)
|
|
| 41 |
+ resp, err := cli.getWithContext(ctx, "/containers/"+options.ContainerID+"/logs", query, nil) |
|
| 42 | 42 |
if err != nil {
|
| 43 | 43 |
return nil, err |
| 44 | 44 |
} |
| ... | ... |
@@ -9,6 +9,10 @@ import ( |
| 9 | 9 |
"net/http" |
| 10 | 10 |
"net/url" |
| 11 | 11 |
"strings" |
| 12 |
+ |
|
| 13 |
+ "github.com/docker/engine-api/client/transport/cancellable" |
|
| 14 |
+ |
|
| 15 |
+ "golang.org/x/net/context" |
|
| 12 | 16 |
) |
| 13 | 17 |
|
| 14 | 18 |
// serverResponse is a wrapper for http API responses. |
| ... | ... |
@@ -20,40 +24,55 @@ type serverResponse struct {
|
| 20 | 20 |
|
| 21 | 21 |
// head sends an http request to the docker API using the method HEAD. |
| 22 | 22 |
func (cli *Client) head(path string, query url.Values, headers map[string][]string) (*serverResponse, error) {
|
| 23 |
- return cli.sendRequest("HEAD", path, query, nil, headers)
|
|
| 23 |
+ return cli.sendRequest(context.Background(), "HEAD", path, query, nil, headers) |
|
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 | 26 |
// get sends an http request to the docker API using the method GET. |
| 27 | 27 |
func (cli *Client) get(path string, query url.Values, headers map[string][]string) (*serverResponse, error) {
|
| 28 |
- return cli.sendRequest("GET", path, query, nil, headers)
|
|
| 28 |
+ return cli.getWithContext(context.Background(), path, query, headers) |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+// getWithContext sends an http request to the docker API using the method GET with a specific go context. |
|
| 32 |
+func (cli *Client) getWithContext(ctx context.Context, path string, query url.Values, headers map[string][]string) (*serverResponse, error) {
|
|
| 33 |
+ return cli.sendRequest(ctx, "GET", path, query, nil, headers) |
|
| 29 | 34 |
} |
| 30 | 35 |
|
| 31 | 36 |
// post sends an http request to the docker API using the method POST. |
| 32 | 37 |
func (cli *Client) post(path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) {
|
| 33 |
- return cli.sendRequest("POST", path, query, body, headers)
|
|
| 38 |
+ return cli.postWithContext(context.Background(), path, query, body, headers) |
|
| 34 | 39 |
} |
| 35 | 40 |
|
| 36 |
-// postRaw sends the raw input to the docker API using the method POST. |
|
| 37 |
-func (cli *Client) postRaw(path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) {
|
|
| 38 |
- return cli.sendClientRequest("POST", path, query, body, headers)
|
|
| 41 |
+// postWithContext sends an http request to the docker API using the method POST with a specific go context. |
|
| 42 |
+func (cli *Client) postWithContext(ctx context.Context, path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) {
|
|
| 43 |
+ return cli.sendRequest(ctx, "POST", path, query, body, headers) |
|
| 44 |
+} |
|
| 45 |
+ |
|
| 46 |
+// postRaw sends the raw input to the docker API using the method POST with a specific go context. |
|
| 47 |
+func (cli *Client) postRaw(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) {
|
|
| 48 |
+ return cli.sendClientRequest(ctx, "POST", path, query, body, headers) |
|
| 39 | 49 |
} |
| 40 | 50 |
|
| 41 | 51 |
// put sends an http request to the docker API using the method PUT. |
| 42 | 52 |
func (cli *Client) put(path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) {
|
| 43 |
- return cli.sendRequest("PUT", path, query, body, headers)
|
|
| 53 |
+ return cli.sendRequest(context.Background(), "PUT", path, query, body, headers) |
|
| 44 | 54 |
} |
| 45 | 55 |
|
| 46 | 56 |
// putRaw sends the raw input to the docker API using the method PUT. |
| 47 | 57 |
func (cli *Client) putRaw(path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) {
|
| 48 |
- return cli.sendClientRequest("PUT", path, query, body, headers)
|
|
| 58 |
+ return cli.putRawWithContext(context.Background(), path, query, body, headers) |
|
| 59 |
+} |
|
| 60 |
+ |
|
| 61 |
+// putRawWithContext sends the raw input to the docker API using the method PUT with a specific go context. |
|
| 62 |
+func (cli *Client) putRawWithContext(ctx context.Context, path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) {
|
|
| 63 |
+ return cli.sendClientRequest(ctx, "PUT", path, query, body, headers) |
|
| 49 | 64 |
} |
| 50 | 65 |
|
| 51 | 66 |
// delete sends an http request to the docker API using the method DELETE. |
| 52 | 67 |
func (cli *Client) delete(path string, query url.Values, headers map[string][]string) (*serverResponse, error) {
|
| 53 |
- return cli.sendRequest("DELETE", path, query, nil, headers)
|
|
| 68 |
+ return cli.sendRequest(context.Background(), "DELETE", path, query, nil, headers) |
|
| 54 | 69 |
} |
| 55 | 70 |
|
| 56 |
-func (cli *Client) sendRequest(method, path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) {
|
|
| 71 |
+func (cli *Client) sendRequest(ctx context.Context, method, path string, query url.Values, body interface{}, headers map[string][]string) (*serverResponse, error) {
|
|
| 57 | 72 |
params, err := encodeData(body) |
| 58 | 73 |
if err != nil {
|
| 59 | 74 |
return nil, err |
| ... | ... |
@@ -66,10 +85,10 @@ func (cli *Client) sendRequest(method, path string, query url.Values, body inter |
| 66 | 66 |
headers["Content-Type"] = []string{"application/json"}
|
| 67 | 67 |
} |
| 68 | 68 |
|
| 69 |
- return cli.sendClientRequest(method, path, query, params, headers) |
|
| 69 |
+ return cli.sendClientRequest(ctx, method, path, query, params, headers) |
|
| 70 | 70 |
} |
| 71 | 71 |
|
| 72 |
-func (cli *Client) sendClientRequest(method, path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) {
|
|
| 72 |
+func (cli *Client) sendClientRequest(ctx context.Context, method, path string, query url.Values, body io.Reader, headers map[string][]string) (*serverResponse, error) {
|
|
| 73 | 73 |
serverResp := &serverResponse{
|
| 74 | 74 |
body: nil, |
| 75 | 75 |
statusCode: -1, |
| ... | ... |
@@ -82,13 +101,13 @@ func (cli *Client) sendClientRequest(method, path string, query url.Values, body |
| 82 | 82 |
|
| 83 | 83 |
req, err := cli.newRequest(method, path, query, body, headers) |
| 84 | 84 |
req.URL.Host = cli.addr |
| 85 |
- req.URL.Scheme = cli.scheme |
|
| 85 |
+ req.URL.Scheme = cli.transport.Scheme() |
|
| 86 | 86 |
|
| 87 | 87 |
if expectedPayload && req.Header.Get("Content-Type") == "" {
|
| 88 | 88 |
req.Header.Set("Content-Type", "text/plain")
|
| 89 | 89 |
} |
| 90 | 90 |
|
| 91 |
- resp, err := cli.httpClient.Do(req) |
|
| 91 |
+ resp, err := cancellable.Do(ctx, cli.transport, req) |
|
| 92 | 92 |
if resp != nil {
|
| 93 | 93 |
serverResp.statusCode = resp.StatusCode |
| 94 | 94 |
} |
| ... | ... |
@@ -98,10 +117,10 @@ func (cli *Client) sendClientRequest(method, path string, query url.Values, body |
| 98 | 98 |
return serverResp, ErrConnectionFailed |
| 99 | 99 |
} |
| 100 | 100 |
|
| 101 |
- if cli.scheme == "http" && strings.Contains(err.Error(), "malformed HTTP response") {
|
|
| 101 |
+ if !cli.transport.Secure() && strings.Contains(err.Error(), "malformed HTTP response") {
|
|
| 102 | 102 |
return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)
|
| 103 | 103 |
} |
| 104 |
- if cli.scheme == "https" && strings.Contains(err.Error(), "remote error: bad certificate") {
|
|
| 104 |
+ if cli.transport.Secure() && strings.Contains(err.Error(), "remote error: bad certificate") {
|
|
| 105 | 105 |
return serverResp, fmt.Errorf("The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: %v", err)
|
| 106 | 106 |
} |
| 107 | 107 |
|
| 108 | 108 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,23 @@ |
| 0 |
+// Copyright 2015 The Go Authors. All rights reserved. |
|
| 1 |
+// Use of this source code is governed by a BSD-style |
|
| 2 |
+// license that can be found in the LICENSE file. |
|
| 3 |
+ |
|
| 4 |
+// +build go1.5 |
|
| 5 |
+ |
|
| 6 |
+package cancellable |
|
| 7 |
+ |
|
| 8 |
+import ( |
|
| 9 |
+ "net/http" |
|
| 10 |
+ |
|
| 11 |
+ "github.com/docker/engine-api/client/transport" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+func canceler(client transport.Sender, req *http.Request) func() {
|
|
| 15 |
+ // TODO(djd): Respect any existing value of req.Cancel. |
|
| 16 |
+ ch := make(chan struct{})
|
|
| 17 |
+ req.Cancel = ch |
|
| 18 |
+ |
|
| 19 |
+ return func() {
|
|
| 20 |
+ close(ch) |
|
| 21 |
+ } |
|
| 22 |
+} |
| 0 | 23 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,27 @@ |
| 0 |
+// Copyright 2015 The Go Authors. All rights reserved. |
|
| 1 |
+// Use of this source code is governed by a BSD-style |
|
| 2 |
+// license that can be found in the LICENSE file. |
|
| 3 |
+ |
|
| 4 |
+// +build !go1.5 |
|
| 5 |
+ |
|
| 6 |
+package cancellable |
|
| 7 |
+ |
|
| 8 |
+import ( |
|
| 9 |
+ "net/http" |
|
| 10 |
+ |
|
| 11 |
+ "github.com/docker/engine-api/client/transport" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+type requestCanceler interface {
|
|
| 15 |
+ CancelRequest(*http.Request) |
|
| 16 |
+} |
|
| 17 |
+ |
|
| 18 |
+func canceler(client transport.Sender, req *http.Request) func() {
|
|
| 19 |
+ rc, ok := client.(requestCanceler) |
|
| 20 |
+ if !ok {
|
|
| 21 |
+ return func() {}
|
|
| 22 |
+ } |
|
| 23 |
+ return func() {
|
|
| 24 |
+ rc.CancelRequest(req) |
|
| 25 |
+ } |
|
| 26 |
+} |
| 0 | 27 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,113 @@ |
| 0 |
+// Copyright 2015 The Go Authors. All rights reserved. |
|
| 1 |
+// Use of this source code is governed by a BSD-style |
|
| 2 |
+// license that can be found in the LICENSE file. |
|
| 3 |
+ |
|
| 4 |
+// Package cancellable provides helper function to cancel http requests. |
|
| 5 |
+package cancellable |
|
| 6 |
+ |
|
| 7 |
+import ( |
|
| 8 |
+ "io" |
|
| 9 |
+ "net/http" |
|
| 10 |
+ |
|
| 11 |
+ "github.com/docker/engine-api/client/transport" |
|
| 12 |
+ |
|
| 13 |
+ "golang.org/x/net/context" |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+func nop() {}
|
|
| 17 |
+ |
|
| 18 |
+var ( |
|
| 19 |
+ testHookContextDoneBeforeHeaders = nop |
|
| 20 |
+ testHookDoReturned = nop |
|
| 21 |
+ testHookDidBodyClose = nop |
|
| 22 |
+) |
|
| 23 |
+ |
|
| 24 |
+// Do sends an HTTP request with the provided transport.Sender and returns an HTTP response. |
|
| 25 |
+// If the client is nil, http.DefaultClient is used. |
|
| 26 |
+// If the context is canceled or times out, ctx.Err() will be returned. |
|
| 27 |
+// |
|
| 28 |
+// FORK INFORMATION: |
|
| 29 |
+// |
|
| 30 |
+// This function deviates from the upstream version in golang.org/x/net/context/ctxhttp by |
|
| 31 |
+// taking a Sender interface rather than a *http.Client directly. That allow us to use |
|
| 32 |
+// this funcion with mocked clients and hijacked connections. |
|
| 33 |
+func Do(ctx context.Context, client transport.Sender, req *http.Request) (*http.Response, error) {
|
|
| 34 |
+ if client == nil {
|
|
| 35 |
+ client = http.DefaultClient |
|
| 36 |
+ } |
|
| 37 |
+ |
|
| 38 |
+ // Request cancelation changed in Go 1.5, see canceler.go and canceler_go14.go. |
|
| 39 |
+ cancel := canceler(client, req) |
|
| 40 |
+ |
|
| 41 |
+ type responseAndError struct {
|
|
| 42 |
+ resp *http.Response |
|
| 43 |
+ err error |
|
| 44 |
+ } |
|
| 45 |
+ result := make(chan responseAndError, 1) |
|
| 46 |
+ |
|
| 47 |
+ go func() {
|
|
| 48 |
+ resp, err := client.Do(req) |
|
| 49 |
+ testHookDoReturned() |
|
| 50 |
+ result <- responseAndError{resp, err}
|
|
| 51 |
+ }() |
|
| 52 |
+ |
|
| 53 |
+ var resp *http.Response |
|
| 54 |
+ |
|
| 55 |
+ select {
|
|
| 56 |
+ case <-ctx.Done(): |
|
| 57 |
+ testHookContextDoneBeforeHeaders() |
|
| 58 |
+ cancel() |
|
| 59 |
+ // Clean up after the goroutine calling client.Do: |
|
| 60 |
+ go func() {
|
|
| 61 |
+ if r := <-result; r.resp != nil && r.resp.Body != nil {
|
|
| 62 |
+ testHookDidBodyClose() |
|
| 63 |
+ r.resp.Body.Close() |
|
| 64 |
+ } |
|
| 65 |
+ }() |
|
| 66 |
+ return nil, ctx.Err() |
|
| 67 |
+ case r := <-result: |
|
| 68 |
+ var err error |
|
| 69 |
+ resp, err = r.resp, r.err |
|
| 70 |
+ if err != nil {
|
|
| 71 |
+ return resp, err |
|
| 72 |
+ } |
|
| 73 |
+ } |
|
| 74 |
+ |
|
| 75 |
+ c := make(chan struct{})
|
|
| 76 |
+ go func() {
|
|
| 77 |
+ select {
|
|
| 78 |
+ case <-ctx.Done(): |
|
| 79 |
+ cancel() |
|
| 80 |
+ case <-c: |
|
| 81 |
+ // The response's Body is closed. |
|
| 82 |
+ } |
|
| 83 |
+ }() |
|
| 84 |
+ resp.Body = ¬ifyingReader{resp.Body, c}
|
|
| 85 |
+ |
|
| 86 |
+ return resp, nil |
|
| 87 |
+} |
|
| 88 |
+ |
|
| 89 |
+// notifyingReader is an io.ReadCloser that closes the notify channel after |
|
| 90 |
+// Close is called or a Read fails on the underlying ReadCloser. |
|
| 91 |
+type notifyingReader struct {
|
|
| 92 |
+ io.ReadCloser |
|
| 93 |
+ notify chan<- struct{}
|
|
| 94 |
+} |
|
| 95 |
+ |
|
| 96 |
+func (r *notifyingReader) Read(p []byte) (int, error) {
|
|
| 97 |
+ n, err := r.ReadCloser.Read(p) |
|
| 98 |
+ if err != nil && r.notify != nil {
|
|
| 99 |
+ close(r.notify) |
|
| 100 |
+ r.notify = nil |
|
| 101 |
+ } |
|
| 102 |
+ return n, err |
|
| 103 |
+} |
|
| 104 |
+ |
|
| 105 |
+func (r *notifyingReader) Close() error {
|
|
| 106 |
+ err := r.ReadCloser.Close() |
|
| 107 |
+ if r.notify != nil {
|
|
| 108 |
+ close(r.notify) |
|
| 109 |
+ r.notify = nil |
|
| 110 |
+ } |
|
| 111 |
+ return err |
|
| 112 |
+} |
| 0 | 113 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,47 @@ |
| 0 |
+package transport |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "crypto/tls" |
|
| 4 |
+ "net/http" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// Sender is an interface that clients must implement |
|
| 8 |
+// to be able to send requests to a remote connection. |
|
| 9 |
+type Sender interface {
|
|
| 10 |
+ // Do sends request to a remote endpoint. |
|
| 11 |
+ Do(*http.Request) (*http.Response, error) |
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+// Client is an interface that abstracts all remote connections. |
|
| 15 |
+type Client interface {
|
|
| 16 |
+ Sender |
|
| 17 |
+ // Secure tells whether the connection is secure or not. |
|
| 18 |
+ Secure() bool |
|
| 19 |
+ // Scheme returns the connection protocol the client uses. |
|
| 20 |
+ Scheme() string |
|
| 21 |
+ // TLSConfig returns any TLS configuration the client uses. |
|
| 22 |
+ TLSConfig() *tls.Config |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+// tlsInfo returns information about the TLS configuration. |
|
| 26 |
+type tlsInfo struct {
|
|
| 27 |
+ tlsConfig *tls.Config |
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+// TLSConfig returns the TLS configuration. |
|
| 31 |
+func (t *tlsInfo) TLSConfig() *tls.Config {
|
|
| 32 |
+ return t.tlsConfig |
|
| 33 |
+} |
|
| 34 |
+ |
|
| 35 |
+// Scheme returns protocol scheme to use. |
|
| 36 |
+func (t *tlsInfo) Scheme() string {
|
|
| 37 |
+ if t.tlsConfig != nil {
|
|
| 38 |
+ return "https" |
|
| 39 |
+ } |
|
| 40 |
+ return "http" |
|
| 41 |
+} |
|
| 42 |
+ |
|
| 43 |
+// Secure returns true if there is a TLS configuration. |
|
| 44 |
+func (t *tlsInfo) Secure() bool {
|
|
| 45 |
+ return t.tlsConfig != nil |
|
| 46 |
+} |
| 0 | 47 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,26 @@ |
| 0 |
+// +build test |
|
| 1 |
+ |
|
| 2 |
+package transport |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "crypto/tls" |
|
| 6 |
+ "net/http" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+type mockClient struct {
|
|
| 10 |
+ *tlsInfo |
|
| 11 |
+ do func(*http.Request) (*http.Response, error) |
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+// NewMockClient returns a mocked client that runs the function supplied as `client.Do` call |
|
| 15 |
+func NewMockClient(tlsConfig *tls.Config, doer func(*http.Request) (*http.Response, error)) Client {
|
|
| 16 |
+ return mockClient{
|
|
| 17 |
+ tlsInfo: &tlsInfo{tlsConfig},
|
|
| 18 |
+ do: doer, |
|
| 19 |
+ } |
|
| 20 |
+} |
|
| 21 |
+ |
|
| 22 |
+// Do executes the supplied function for the mock. |
|
| 23 |
+func (m mockClient) Do(req *http.Request) (*http.Response, error) {
|
|
| 24 |
+ return m.do(req) |
|
| 25 |
+} |
| 0 | 26 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,57 @@ |
| 0 |
+// Package transport provides function to send request to remote endpoints. |
|
| 1 |
+package transport |
|
| 2 |
+ |
|
| 3 |
+import ( |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "net/http" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/go-connections/sockets" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+// apiTransport holds information about the http transport to connect with the API. |
|
| 11 |
+type apiTransport struct {
|
|
| 12 |
+ *http.Client |
|
| 13 |
+ *tlsInfo |
|
| 14 |
+ transport *http.Transport |
|
| 15 |
+} |
|
| 16 |
+ |
|
| 17 |
+// NewTransportWithHTTP creates a new transport based on the provided proto, address and http client. |
|
| 18 |
+// It uses Docker's default http transport configuration if the client is nil. |
|
| 19 |
+// It does not modify the client's transport if it's not nil. |
|
| 20 |
+func NewTransportWithHTTP(proto, addr string, client *http.Client) (Client, error) {
|
|
| 21 |
+ var transport *http.Transport |
|
| 22 |
+ |
|
| 23 |
+ if client != nil {
|
|
| 24 |
+ tr, ok := client.Transport.(*http.Transport) |
|
| 25 |
+ if !ok {
|
|
| 26 |
+ return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", client.Transport)
|
|
| 27 |
+ } |
|
| 28 |
+ transport = tr |
|
| 29 |
+ } else {
|
|
| 30 |
+ transport = defaultTransport(proto, addr) |
|
| 31 |
+ client = &http.Client{
|
|
| 32 |
+ Transport: transport, |
|
| 33 |
+ } |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ return &apiTransport{
|
|
| 37 |
+ Client: client, |
|
| 38 |
+ tlsInfo: &tlsInfo{transport.TLSClientConfig},
|
|
| 39 |
+ transport: transport, |
|
| 40 |
+ }, nil |
|
| 41 |
+} |
|
| 42 |
+ |
|
| 43 |
+// CancelRequest stops a request execution. |
|
| 44 |
+func (a *apiTransport) CancelRequest(req *http.Request) {
|
|
| 45 |
+ a.transport.CancelRequest(req) |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+// defaultTransport creates a new http.Transport with Docker's |
|
| 49 |
+// default transport configuration. |
|
| 50 |
+func defaultTransport(proto, addr string) *http.Transport {
|
|
| 51 |
+ tr := new(http.Transport) |
|
| 52 |
+ sockets.ConfigureTransport(tr, proto, addr) |
|
| 53 |
+ return tr |
|
| 54 |
+} |
|
| 55 |
+ |
|
| 56 |
+var _ Client = &apiTransport{}
|
| ... | ... |
@@ -3,13 +3,15 @@ package client |
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
|
| 6 |
+ "golang.org/x/net/context" |
|
| 7 |
+ |
|
| 6 | 8 |
"github.com/docker/engine-api/types" |
| 7 | 9 |
) |
| 8 | 10 |
|
| 9 | 11 |
// ContainerWait pauses execution util a container is exits. |
| 10 | 12 |
// It returns the API status code as response of its readiness. |
| 11 |
-func (cli *Client) ContainerWait(containerID string) (int, error) {
|
|
| 12 |
- resp, err := cli.post("/containers/"+containerID+"/wait", nil, nil, nil)
|
|
| 13 |
+func (cli *Client) ContainerWait(ctx context.Context, containerID string) (int, error) {
|
|
| 14 |
+ resp, err := cli.postWithContext(ctx, "/containers/"+containerID+"/wait", nil, nil, nil) |
|
| 13 | 15 |
if err != nil {
|
| 14 | 16 |
return -1, err |
| 15 | 17 |
} |
| ... | ... |
@@ -72,12 +72,6 @@ func (n NetworkMode) IsUserDefined() bool {
|
| 72 | 72 |
return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() |
| 73 | 73 |
} |
| 74 | 74 |
|
| 75 |
-// IsPreDefinedNetwork indicates if a network is predefined by the daemon |
|
| 76 |
-func IsPreDefinedNetwork(network string) bool {
|
|
| 77 |
- n := NetworkMode(network) |
|
| 78 |
- return n.IsBridge() || n.IsHost() || n.IsNone() |
|
| 79 |
-} |
|
| 80 |
- |
|
| 81 | 75 |
//UserDefined indicates user-created network |
| 82 | 76 |
func (n NetworkMode) UserDefined() string {
|
| 83 | 77 |
if n.IsUserDefined() {
|
| ... | ... |
@@ -49,11 +49,6 @@ func (n NetworkMode) NetworkName() string {
|
| 49 | 49 |
return "" |
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 |
-// IsPreDefinedNetwork indicates if a network is predefined by the daemon |
|
| 53 |
-func IsPreDefinedNetwork(network string) bool {
|
|
| 54 |
- return false |
|
| 55 |
-} |
|
| 56 |
- |
|
| 57 | 52 |
// ValidateNetMode ensures that the various combinations of requested |
| 58 | 53 |
// network settings are valid. |
| 59 | 54 |
func ValidateNetMode(c *Config, hc *HostConfig) error {
|
| ... | ... |
@@ -387,6 +387,7 @@ type NetworkResource struct {
|
| 387 | 387 |
ID string `json:"Id"` |
| 388 | 388 |
Scope string |
| 389 | 389 |
Driver string |
| 390 |
+ EnableIPv6 bool |
|
| 390 | 391 |
IPAM network.IPAM |
| 391 | 392 |
Internal bool |
| 392 | 393 |
Containers map[string]EndpointResource |
| ... | ... |
@@ -407,6 +408,7 @@ type NetworkCreate struct {
|
| 407 | 407 |
Name string |
| 408 | 408 |
CheckDuplicate bool |
| 409 | 409 |
Driver string |
| 410 |
+ EnableIPv6 bool |
|
| 410 | 411 |
IPAM network.IPAM |
| 411 | 412 |
Internal bool |
| 412 | 413 |
Options map[string]string |
| 413 | 414 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,89 @@ |
| 0 |
+package sockets |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "errors" |
|
| 4 |
+ "net" |
|
| 5 |
+ "sync" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+var errClosed = errors.New("use of closed network connection")
|
|
| 9 |
+ |
|
| 10 |
+// InmemSocket implements net.Listener using in-memory only connections. |
|
| 11 |
+type InmemSocket struct {
|
|
| 12 |
+ chConn chan net.Conn |
|
| 13 |
+ chClose chan struct{}
|
|
| 14 |
+ addr string |
|
| 15 |
+ mu sync.Mutex |
|
| 16 |
+} |
|
| 17 |
+ |
|
| 18 |
+// dummyAddr is used to satisfy net.Addr for the in-mem socket |
|
| 19 |
+// it is just stored as a string and returns the string for all calls |
|
| 20 |
+type dummyAddr string |
|
| 21 |
+ |
|
| 22 |
+// NewInmemSocket creates an in-memory only net.Listener |
|
| 23 |
+// The addr argument can be any string, but is used to satisfy the `Addr()` part |
|
| 24 |
+// of the net.Listener interface |
|
| 25 |
+func NewInmemSocket(addr string, bufSize int) *InmemSocket {
|
|
| 26 |
+ return &InmemSocket{
|
|
| 27 |
+ chConn: make(chan net.Conn, bufSize), |
|
| 28 |
+ chClose: make(chan struct{}),
|
|
| 29 |
+ addr: addr, |
|
| 30 |
+ } |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 33 |
+// Addr returns the socket's addr string to satisfy net.Listener |
|
| 34 |
+func (s *InmemSocket) Addr() net.Addr {
|
|
| 35 |
+ return dummyAddr(s.addr) |
|
| 36 |
+} |
|
| 37 |
+ |
|
| 38 |
+// Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn. |
|
| 39 |
+func (s *InmemSocket) Accept() (net.Conn, error) {
|
|
| 40 |
+ select {
|
|
| 41 |
+ case conn := <-s.chConn: |
|
| 42 |
+ return conn, nil |
|
| 43 |
+ case <-s.chClose: |
|
| 44 |
+ return nil, errClosed |
|
| 45 |
+ } |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+// Close closes the listener. It will be unavailable for use once closed. |
|
| 49 |
+func (s *InmemSocket) Close() error {
|
|
| 50 |
+ s.mu.Lock() |
|
| 51 |
+ defer s.mu.Unlock() |
|
| 52 |
+ select {
|
|
| 53 |
+ case <-s.chClose: |
|
| 54 |
+ default: |
|
| 55 |
+ close(s.chClose) |
|
| 56 |
+ } |
|
| 57 |
+ return nil |
|
| 58 |
+} |
|
| 59 |
+ |
|
| 60 |
+// Dial is used to establish a connection with the in-mem server |
|
| 61 |
+func (s *InmemSocket) Dial(network, addr string) (net.Conn, error) {
|
|
| 62 |
+ srvConn, clientConn := net.Pipe() |
|
| 63 |
+ select {
|
|
| 64 |
+ case s.chConn <- srvConn: |
|
| 65 |
+ case <-s.chClose: |
|
| 66 |
+ return nil, errClosed |
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ return clientConn, nil |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+// Network returns the addr string, satisfies net.Addr |
|
| 73 |
+func (a dummyAddr) Network() string {
|
|
| 74 |
+ return string(a) |
|
| 75 |
+} |
|
| 76 |
+ |
|
| 77 |
+// String returns the string form |
|
| 78 |
+func (a dummyAddr) String() string {
|
|
| 79 |
+ return string(a) |
|
| 80 |
+} |
|
| 81 |
+ |
|
| 82 |
+// timeoutError is used when there is a timeout with a connection |
|
| 83 |
+// this implements the net.Error interface |
|
| 84 |
+type timeoutError struct{}
|
|
| 85 |
+ |
|
| 86 |
+func (e *timeoutError) Error() string { return "i/o timeout" }
|
|
| 87 |
+func (e *timeoutError) Timeout() bool { return true }
|
|
| 88 |
+func (e *timeoutError) Temporary() bool { return true }
|
| 0 | 89 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,35 @@ |
| 0 |
+// Package sockets provides helper functions to create and configure Unix or TCP sockets. |
|
| 1 |
+package sockets |
|
| 2 |
+ |
|
| 3 |
+import ( |
|
| 4 |
+ "net" |
|
| 5 |
+ "net/http" |
|
| 6 |
+ "time" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+// Why 32? See https://github.com/docker/docker/pull/8035. |
|
| 10 |
+const defaulTimeout = 32 * time.Second |
|
| 11 |
+ |
|
| 12 |
+// ConfigureTransport configures the specified Transport according to the |
|
| 13 |
+// specified proto and addr. |
|
| 14 |
+// If the proto is unix (using a unix socket to communicate) the compression |
|
| 15 |
+// is disabled. |
|
| 16 |
+func ConfigureTransport(tr *http.Transport, proto, addr string) {
|
|
| 17 |
+ switch proto {
|
|
| 18 |
+ case "unix": |
|
| 19 |
+ // No need for compression in local communications. |
|
| 20 |
+ tr.DisableCompression = true |
|
| 21 |
+ tr.Dial = func(_, _ string) (net.Conn, error) {
|
|
| 22 |
+ return net.DialTimeout(proto, addr, defaulTimeout) |
|
| 23 |
+ } |
|
| 24 |
+ case "npipe": |
|
| 25 |
+ // No need for compression in local communications. |
|
| 26 |
+ tr.DisableCompression = true |
|
| 27 |
+ tr.Dial = func(_, _ string) (net.Conn, error) {
|
|
| 28 |
+ return DialPipe(addr, defaulTimeout) |
|
| 29 |
+ } |
|
| 30 |
+ default: |
|
| 31 |
+ tr.Proxy = http.ProxyFromEnvironment |
|
| 32 |
+ tr.Dial = (&net.Dialer{Timeout: defaulTimeout}).Dial
|
|
| 33 |
+ } |
|
| 34 |
+} |
| 0 | 35 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,15 @@ |
| 0 |
+// +build !windows |
|
| 1 |
+ |
|
| 2 |
+package sockets |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "net" |
|
| 6 |
+ "syscall" |
|
| 7 |
+ "time" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+// DialPipe connects to a Windows named pipe. |
|
| 11 |
+// This is not supported on other OSes. |
|
| 12 |
+func DialPipe(_ string, _ time.Duration) (net.Conn, error) {
|
|
| 13 |
+ return nil, syscall.EAFNOSUPPORT |
|
| 14 |
+} |
| 0 | 15 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,13 @@ |
| 0 |
+package sockets |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "net" |
|
| 4 |
+ "time" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/Microsoft/go-winio" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+// DialPipe connects to a Windows named pipe. |
|
| 10 |
+func DialPipe(addr string, timeout time.Duration) (net.Conn, error) {
|
|
| 11 |
+ return winio.DialPipe(addr, &timeout) |
|
| 12 |
+} |
| ... | ... |
@@ -4,8 +4,6 @@ package sockets |
| 4 | 4 |
import ( |
| 5 | 5 |
"crypto/tls" |
| 6 | 6 |
"net" |
| 7 |
- "net/http" |
|
| 8 |
- "time" |
|
| 9 | 7 |
) |
| 10 | 8 |
|
| 11 | 9 |
// 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) {
|
| 22 | 22 |
} |
| 23 | 23 |
return l, nil |
| 24 | 24 |
} |
| 25 |
- |
|
| 26 |
-// ConfigureTCPTransport configures the specified Transport according to the |
|
| 27 |
-// specified proto and addr. |
|
| 28 |
-// If the proto is unix (using a unix socket to communicate) the compression |
|
| 29 |
-// is disabled. |
|
| 30 |
-func ConfigureTCPTransport(tr *http.Transport, proto, addr string) {
|
|
| 31 |
- // Why 32? See https://github.com/docker/docker/pull/8035. |
|
| 32 |
- timeout := 32 * time.Second |
|
| 33 |
- if proto == "unix" {
|
|
| 34 |
- // No need for compression in local communications. |
|
| 35 |
- tr.DisableCompression = true |
|
| 36 |
- tr.Dial = func(_, _ string) (net.Conn, error) {
|
|
| 37 |
- return net.DialTimeout(proto, addr, timeout) |
|
| 38 |
- } |
|
| 39 |
- } else {
|
|
| 40 |
- tr.Proxy = http.ProxyFromEnvironment |
|
| 41 |
- tr.Dial = (&net.Dialer{Timeout: timeout}).Dial
|
|
| 42 |
- } |
|
| 43 |
-} |
| ... | ... |
@@ -41,12 +41,6 @@ var acceptedCBCCiphers = []uint16{
|
| 41 | 41 |
tls.TLS_RSA_WITH_AES_128_CBC_SHA, |
| 42 | 42 |
} |
| 43 | 43 |
|
| 44 |
-// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) |
|
| 45 |
-var clientCipherSuites = []uint16{
|
|
| 46 |
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
|
| 47 |
- tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
|
| 48 |
-} |
|
| 49 |
- |
|
| 50 | 44 |
// DefaultServerAcceptedCiphers should be uses by code which already has a crypto/tls |
| 51 | 45 |
// options struct but wants to use a commonly accepted set of TLS cipher suites, with |
| 52 | 46 |
// known weak algorithms removed. |
| ... | ... |
@@ -91,7 +85,7 @@ func certPool(caFile string) (*x509.CertPool, error) {
|
| 91 | 91 |
func Client(options Options) (*tls.Config, error) {
|
| 92 | 92 |
tlsConfig := ClientDefault |
| 93 | 93 |
tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify |
| 94 |
- if !options.InsecureSkipVerify {
|
|
| 94 |
+ if !options.InsecureSkipVerify && options.CAFile != "" {
|
|
| 95 | 95 |
CAs, err := certPool(options.CAFile) |
| 96 | 96 |
if err != nil {
|
| 97 | 97 |
return nil, err |
| ... | ... |
@@ -99,7 +93,7 @@ func Client(options Options) (*tls.Config, error) {
|
| 99 | 99 |
tlsConfig.RootCAs = CAs |
| 100 | 100 |
} |
| 101 | 101 |
|
| 102 |
- if options.CertFile != "" && options.KeyFile != "" {
|
|
| 102 |
+ if options.CertFile != "" || options.KeyFile != "" {
|
|
| 103 | 103 |
tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile) |
| 104 | 104 |
if err != nil {
|
| 105 | 105 |
return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err)
|
| 106 | 106 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,17 @@ |
| 0 |
+// +build go1.5 |
|
| 1 |
+ |
|
| 2 |
+// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. |
|
| 3 |
+// |
|
| 4 |
+package tlsconfig |
|
| 5 |
+ |
|
| 6 |
+import ( |
|
| 7 |
+ "crypto/tls" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) |
|
| 11 |
+var clientCipherSuites = []uint16{
|
|
| 12 |
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, |
|
| 13 |
+ tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, |
|
| 14 |
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
|
| 15 |
+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
|
| 16 |
+} |
| 0 | 17 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,15 @@ |
| 0 |
+// +build !go1.5 |
|
| 1 |
+ |
|
| 2 |
+// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers. |
|
| 3 |
+// |
|
| 4 |
+package tlsconfig |
|
| 5 |
+ |
|
| 6 |
+import ( |
|
| 7 |
+ "crypto/tls" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set) |
|
| 11 |
+var clientCipherSuites = []uint16{
|
|
| 12 |
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
|
| 13 |
+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
|
| 14 |
+} |