update vendor

Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
This commit is contained in:
Jess Frazelle 2018-06-06 12:10:36 -04:00
parent eaf071b3ef
commit fa2c3fedcc
No known key found for this signature in database
GPG key ID: 18F3685C0022BFF3
153 changed files with 8616 additions and 1041 deletions

View file

@ -21,7 +21,7 @@
- staticcheck $(go list ./... | grep -v vendor)
- test -z "$(golint ./... | grep -v vendor | tee /dev/stderr)"
- test -z "$(gofmt -s -l . | grep -v vendor | tee /dev/stderr)"
- DOCKER_API_VERSION=1.35 make dind dtest
- DOCKER_API_VERSION=1.37 make dind dtest
- make release
after_success:
- bash <(curl -s https://codecov.io/bash)

34
Gopkg.lock generated
View file

@ -32,7 +32,7 @@
branch = "master"
name = "github.com/containerd/continuity"
packages = ["pathdriver"]
revision = "c6cef34830231743494fe2969284df7b82cc0ad0"
revision = "d3c23511c1bf5851696cba83143d9cbcd666869b"
[[projects]]
branch = "master"
@ -42,7 +42,7 @@
"cli/config/credentials",
"opts"
]
revision = "a6b10c2e8524707a3e6168103bded4b1d7ede330"
revision = "90f8ce8a5db263842af7bef3726f6c4d6937d85e"
[[projects]]
branch = "master"
@ -65,7 +65,7 @@
"registry/storage/cache",
"registry/storage/cache/memory"
]
revision = "83389a148052d74ac602f5f1d62f86ff2f3c4aa5"
revision = "f0cc927784781fa395c06317c58dea2841ece3a9"
[[projects]]
branch = "master"
@ -103,13 +103,13 @@
"registry",
"registry/resumable"
]
revision = "38162e96552bd30e510e355cd44d801f53bac5ae"
revision = "fd2f2a919e392b96de74795ae9af2dc5e510bc4c"
[[projects]]
branch = "master"
name = "github.com/docker/docker-ce"
packages = ["components/cli/cli/config"]
revision = "14ad0d5267086c3d13d1daa16d7de2f087c9a5d1"
revision = "370137f15d67e96f4d4435fc868fb2deec6f1f89"
[[projects]]
name = "github.com/docker/docker-credential-helpers"
@ -175,20 +175,20 @@
[[projects]]
name = "github.com/gorilla/context"
packages = ["."]
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
version = "v1.1"
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
version = "v1.1.1"
[[projects]]
name = "github.com/gorilla/mux"
packages = ["."]
revision = "53c1911da2b537f792e7cafcb446b05ffe33b996"
version = "v1.6.1"
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
version = "v1.6.2"
[[projects]]
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
revision = "3247c84500bff8d9fb6d579d800f20b3e091582c"
version = "v1.0.0"
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
version = "v1.0.1"
[[projects]]
branch = "master"
@ -236,7 +236,7 @@
"prometheus",
"prometheus/promhttp"
]
revision = "82f5ff156b29e276022b1a958f7d385870fb9814"
revision = "208fa994be3bd65c0de04f506db92852b581bc4a"
[[projects]]
branch = "master"
@ -252,7 +252,7 @@
"internal/bitbucket.org/ww/goautoneg",
"model"
]
revision = "d811d2e9bf898806ecfb6ef6296774b13ffc314c"
revision = "7600349dcfe1abd18d72d3a1770870d9800a7801"
[[projects]]
branch = "master"
@ -263,7 +263,7 @@
"nfs",
"xfs"
]
revision = "8b1c2da0d56deffdbb9e48d4414b4e674bd8083e"
revision = "94663424ae5ae9856b40a9f170762b4197024661"
[[projects]]
name = "github.com/sirupsen/logrus"
@ -281,7 +281,7 @@
branch = "master"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
revision = "2d027ae1dddd4694d54f7a8b6cbe78dca8720226"
revision = "b47b1587369238182299fe4dad77d05b8b461e06"
[[projects]]
branch = "master"
@ -292,7 +292,7 @@
"internal/socks",
"proxy"
]
revision = "2491c5de3490fced2f6cff376127c667efeed857"
revision = "1e491301e022f8f977054da4c2d852decd59571f"
[[projects]]
branch = "master"
@ -301,7 +301,7 @@
"unix",
"windows"
]
revision = "d0faeb539838e250bd0a9db4182d48d4a1915181"
revision = "538ab54ba952cc4c7c705fa213fbf7993c97c175"
[solve-meta]
analyzer-name = "dep"

View file

@ -74,7 +74,7 @@ staticcheck: ## Verifies `staticcheck` passes
cover: ## Runs go test with coverage
@echo "" > coverage.txt
@for d in $(shell $(GO) list ./... | grep -v vendor); do \
$(GO) test -coverprofile=profile.out -covermode=atomic "$$d"; \
$(GO) test -race -coverprofile=profile.out -covermode=atomic "$$d"; \
if [ -f profile.out ]; then \
cat profile.out >> coverage.txt; \
rm profile.out; \
@ -144,7 +144,7 @@ clean: ## Cleanup any build binaries or packages
@echo "+ $@"
$(RM) $(NAME)
$(RM) -r $(BUILDDIR)
$(RM) -r $(CURDIR)/.certs
sudo $(RM) -r $(CURDIR)/.certs
# set the graph driver as the current graphdriver if not set
DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //'))
@ -161,7 +161,7 @@ endif
.PHONY: dind
DIND_CONTAINER=reg-dind
DIND_DOCKER_IMAGE=r.j3ss.co/docker:userns
dind: ## Starts a docker-in-docker container for running the tests with
dind: stop-dind ## Starts a docker-in-docker container for running the tests with
docker run -d \
--name $(DIND_CONTAINER) \
--privileged \
@ -179,6 +179,10 @@ dind: ## Starts a docker-in-docker container for running the tests with
--tlskey=/etc/docker/ssl/server.key \
--tlscert=/etc/docker/ssl/server.cert
.PHONY: stop-dind
stop-dind: ## Stops the docker-in-docker container
@docker rm -f $(DIND_CONTAINER) >/dev/null 2>&1 || true
.PHONY: dtest
DOCKER_IMAGE := reg-dev
dtest: ## Run the tests in a docker container
@ -195,7 +199,7 @@ dtest: ## Run the tests in a docker container
-e DOCKER_CERT_PATH=/etc/docker/ssl \
-e DOCKER_API_VERSION \
$(DOCKER_IMAGE) \
make test cover
make test
.PHONY: help
help:

View file

@ -572,8 +572,16 @@ func (c *context) Apply(resource Resource) error {
// the context. Otherwise identical to filepath.Walk, the path argument is
// corrected to be contained within the context.
func (c *context) Walk(fn filepath.WalkFunc) error {
return c.pathDriver.Walk(c.root, func(p string, fi os.FileInfo, err error) error {
contained, err := c.contain(p)
root := c.root
fi, err := c.driver.Lstat(c.root)
if err == nil && fi.Mode()&os.ModeSymlink != 0 {
root, err = c.driver.Readlink(c.root)
if err != nil {
return err
}
}
return c.pathDriver.Walk(root, func(p string, fi os.FileInfo, err error) error {
contained, err := c.containWithRoot(p, root)
return fn(contained, fi, err)
})
}
@ -592,7 +600,15 @@ func (c *context) fullpath(p string) (string, error) {
// contain cleans and santizes the filesystem path p to be an absolute path,
// effectively relative to the context root.
func (c *context) contain(p string) (string, error) {
sanitized, err := c.pathDriver.Rel(c.root, p)
return c.containWithRoot(p, c.root)
}
// containWithRoot cleans and santizes the filesystem path p to be an absolute path,
// effectively relative to the passed root. Extra care should be used when calling this
// instead of contain. This is needed for Walk, as if context root is a symlink,
// it must be evaluated prior to the Walk
func (c *context) containWithRoot(p string, root string) (string, error) {
sanitized, err := c.pathDriver.Rel(root, p)
if err != nil {
return "", err
}

View file

@ -66,7 +66,7 @@ func BuildManifest(ctx Context) (*Manifest, error) {
return fmt.Errorf("error walking %s: %v", p, err)
}
if p == "/" {
if p == string(os.PathSeparator) {
// skip root
return nil
}

View file

@ -17,12 +17,12 @@ func SetupRootCommand(rootCmd *cobra.Command) {
cobra.AddTemplateFunc("operationSubCommands", operationSubCommands)
cobra.AddTemplateFunc("managementSubCommands", managementSubCommands)
cobra.AddTemplateFunc("wrappedFlagUsages", wrappedFlagUsages)
cobra.AddTemplateFunc("useLine", UseLine)
rootCmd.SetUsageTemplate(usageTemplate)
rootCmd.SetHelpTemplate(helpTemplate)
rootCmd.SetFlagErrorFunc(FlagErrorFunc)
rootCmd.SetHelpCommand(helpCommand)
rootCmd.SetVersionTemplate("Docker version {{.Version}}\n")
rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")
@ -99,19 +99,9 @@ func managementSubCommands(cmd *cobra.Command) []*cobra.Command {
return cmds
}
// UseLine returns the usage line for a command. This implementation is different
// from the default Command.UseLine in that it does not add a `[flags]` to the
// end of the line.
func UseLine(cmd *cobra.Command) string {
if cmd.HasParent() {
return cmd.Parent().CommandPath() + " " + cmd.Use
}
return cmd.Use
}
var usageTemplate = `Usage:
{{- if not .HasSubCommands}} {{ useLine . }}{{end}}
{{- if not .HasSubCommands}} {{.UseLine}}{{end}}
{{- if .HasSubCommands}} {{ .CommandPath}} COMMAND{{end}}
{{ .Short | trim }}

View file

@ -3,6 +3,7 @@ package configfile
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
@ -46,6 +47,7 @@ type ConfigFile struct {
Proxies map[string]ProxyConfig `json:"proxies,omitempty"`
Experimental string `json:"experimental,omitempty"`
Orchestrator string `json:"orchestrator,omitempty"`
Kubernetes *KubernetesConfig `json:"kubernetes,omitempty"`
}
// ProxyConfig contains proxy configuration settings
@ -56,6 +58,11 @@ type ProxyConfig struct {
FTPProxy string `json:"ftpProxy,omitempty"`
}
// KubernetesConfig contains Kubernetes orchestrator settings
type KubernetesConfig struct {
AllNamespaces string `json:"allNamespaces,omitempty"`
}
// New initializes an empty configuration file for the given filename 'fn'
func New(fn string) *ConfigFile {
return &ConfigFile{
@ -119,7 +126,7 @@ func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
ac.ServerAddress = addr
configFile.AuthConfigs[addr] = ac
}
return nil
return checkKubernetesConfiguration(configFile.Kubernetes)
}
// ContainsAuth returns whether there is authentication configured
@ -312,3 +319,17 @@ func (configFile *ConfigFile) GetAllCredentials() (map[string]types.AuthConfig,
func (configFile *ConfigFile) GetFilename() string {
return configFile.Filename
}
func checkKubernetesConfiguration(kubeConfig *KubernetesConfig) error {
if kubeConfig == nil {
return nil
}
switch kubeConfig.AllNamespaces {
case "":
case "enabled":
case "disabled":
default:
return fmt.Errorf("invalid 'kubernetes.allNamespaces' value, should be 'enabled' or 'disabled': %s", kubeConfig.AllNamespaces)
}
return nil
}

View file

@ -371,3 +371,45 @@ func TestGetAllCredentialsCredHelperOverridesDefaultStore(t *testing.T) {
assert.Check(t, is.Equal(1, testCredsStore.(*mockNativeStore).GetAllCallCount))
assert.Check(t, is.Equal(0, testCredHelper.(*mockNativeStore).GetAllCallCount))
}
func TestCheckKubernetesConfigurationRaiseAnErrorOnInvalidValue(t *testing.T) {
testCases := []struct {
name string
config *KubernetesConfig
expectError bool
}{
{
"no kubernetes config is valid",
nil,
false,
},
{
"enabled is valid",
&KubernetesConfig{AllNamespaces: "enabled"},
false,
},
{
"disabled is valid",
&KubernetesConfig{AllNamespaces: "disabled"},
false,
},
{
"empty string is valid",
&KubernetesConfig{AllNamespaces: ""},
false,
},
{
"other value is invalid",
&KubernetesConfig{AllNamespaces: "unknown"},
true,
},
}
for _, test := range testCases {
err := checkKubernetesConfiguration(test.config)
if test.expectError {
assert.Assert(t, err != nil, test.name)
} else {
assert.NilError(t, err, test.name)
}
}
}

View file

@ -9,6 +9,7 @@ BINARY_NATIVE_IMAGE_NAME = docker-cli-native$(IMAGE_TAG)
LINTER_IMAGE_NAME = docker-cli-lint$(IMAGE_TAG)
CROSS_IMAGE_NAME = docker-cli-cross$(IMAGE_TAG)
VALIDATE_IMAGE_NAME = docker-cli-shell-validate$(IMAGE_TAG)
E2E_IMAGE_NAME = docker-cli-e2e$(IMAGE_TAG)
MOUNTS = -v "$(CURDIR)":/go/src/github.com/docker/cli
VERSION = $(shell cat VERSION)
ENVVARS = -e VERSION=$(VERSION) -e GITCOMMIT -e PLATFORM
@ -35,6 +36,10 @@ build_shell_validate_image:
build_binary_native_image:
docker build -t $(BINARY_NATIVE_IMAGE_NAME) -f ./dockerfiles/Dockerfile.binary-native .
.PHONY: build_e2e_image
build_e2e_image:
docker build -t $(E2E_IMAGE_NAME) --build-arg VERSION=$(VERSION) --build-arg GITCOMMIT=$(GITCOMMIT) -f ./dockerfiles/Dockerfile.e2e .
# build executable using a container
binary: build_binary_native_image
@ -114,5 +119,5 @@ shellcheck: build_shell_validate_image
docker run -ti --rm $(ENVVARS) $(MOUNTS) $(VALIDATE_IMAGE_NAME) make shellcheck
.PHONY: test-e2e
test-e2e: binary
./scripts/test/e2e/wrapper
test-e2e: build_e2e_image
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock $(E2E_IMAGE_NAME)

View file

@ -1,19 +1,21 @@
github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
github.com/containerd/continuity d8fb8589b0e8e85b8c8bbaa8840226d0dfeb7371
github.com/coreos/etcd v3.2.1
github.com/cpuguy83/go-md2man v1.0.8
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
github.com/docker/docker ed7b6428c133e7c59404251a09b7d6b02fa83cc2
github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5
github.com/docker/docker d37f5c6bdf788a6cb82c07fb707e31a240eff5f9
github.com/docker/docker-credential-helpers 3c90bd29a46b943b2a9842987b58fb91a7c1819b
# the docker/go package contains a customized version of canonical/json
# and is used by Notary. The package is periodically rebased on current Go versions.
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
github.com/docker/swarmkit 49a9d7f6ba3c1925262641e694c18eb43575f74b
github.com/docker/swarmkit bd69f6e8e301645afd344913fa1ede53a0a111fb
github.com/emicklei/go-restful ff4f55a206334ef123e4f79bbf348980da81ca46
github.com/emicklei/go-restful-swagger12 dcef7f55730566d41eae5db10e7d6981829720f6
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
@ -34,6 +36,7 @@ github.com/go-openapi/spec 6aced65f8501fe1217321abf0749d354824ba2ff
github.com/go-openapi/swag 1d0bd113de87027671077d3c71eb3ac5d7dbba72
github.com/gregjones/httpcache c1f8028e62adb3d518b823a2f8e6a95c38bdd3aa
github.com/grpc-ecosystem/grpc-gateway 1a03ca3bad1e1ebadaedd3abb76bc58d4ac8143b
github.com/hashicorp/golang-lru 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
github.com/howeyc/gopass 3ca23474a7c7203e0a0a070fd33508f6efdb9b3d
github.com/imdario/mergo 9d5f1277e9a8ed20c3684bda8fde67c05628518c # v0.3.4
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
@ -41,10 +44,12 @@ github.com/juju/ratelimit 5b9ff866471762aa2ab2dced63c9fb6f53921342
github.com/json-iterator/go 6240e1e7983a85228f7fd9c3e1b6932d46ec58e2
github.com/mailru/easyjson d5b7844b561a7bc640052f1b935f7b800330d7e0
github.com/mattn/go-shellwords v1.0.3
github.com/matttproud/golang_protobuf_extensions v1.0.0
github.com/Microsoft/go-winio v0.4.6
github.com/miekg/pkcs11 5f6e0d0dad6f472df908c8e968a98ef00c9224bb
github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715
github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448
github.com/opencontainers/image-spec v1.0.1
@ -52,20 +57,24 @@ github.com/opencontainers/runc 4fc53a81fb7c994640722ac585fa9ca548971871
github.com/peterbourgon/diskv 5f041e8faa004a95c88a202771f4cc3e991971e6
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
github.com/pmezard/go-difflib v1.0.0
github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8
github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
github.com/PuerkitoBio/purell 8a290539e2e8629dbc4e6bad948158f790ec31f4
github.com/PuerkitoBio/urlesc 5bd2802263f21d8788851d5305584c82a5c75d7e
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
github.com/sirupsen/logrus v1.0.3
github.com/spf13/cobra 34ceca591bcf34a17a8b7bad5b3ce5f9c165bee5
github.com/spf13/pflag 97afa5e7ca8a08a383cb259e06636b5e2cc7897f
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.1
github.com/theupdateframework/notary v0.6.1
github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
golang.org/x/net a8b9294777976932365dabb6640cf1468d95c70f
golang.org/x/net 5561cd9b4330353950f399814f427425c0a26fd2
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
@ -79,5 +88,4 @@ k8s.io/apimachinery kubernetes-1.8.2
k8s.io/client-go kubernetes-1.8.2
k8s.io/kubernetes v1.8.2
k8s.io/kube-openapi 61b46af70dfed79c6d24530cd23b41440a7f22a5
vbom.ml/util 928aaa586d7718c70f4090ddf83f2b34c16fdc8d
github.com/hashicorp/golang-lru 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
vbom.ml/util 928aaa586d7718c70f4090ddf83f2b34c16fdc8d

View file

@ -1,4 +1,4 @@
FROM golang:1.8-alpine
FROM golang:1.10-alpine
ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution
ENV DOCKER_BUILDTAGS include_oss include_gcs

View file

@ -8,7 +8,7 @@ machine:
post:
# go
- gvm install go1.8 --prefer-binary --name=stable
- gvm install go1.10 --prefer-binary --name=stable
environment:
# Convenient shortcuts to "common" locations

View file

@ -2,7 +2,7 @@
url = git@github.com:docker/docker-ce-packaging
branch = master
[component "engine"]
url = git@github.com:moby/moby
url = git@github.com:docker/engine
branch = master
[component "cli"]
url = git@github.com:docker/cli

View file

@ -17,12 +17,12 @@ func SetupRootCommand(rootCmd *cobra.Command) {
cobra.AddTemplateFunc("operationSubCommands", operationSubCommands)
cobra.AddTemplateFunc("managementSubCommands", managementSubCommands)
cobra.AddTemplateFunc("wrappedFlagUsages", wrappedFlagUsages)
cobra.AddTemplateFunc("useLine", UseLine)
rootCmd.SetUsageTemplate(usageTemplate)
rootCmd.SetHelpTemplate(helpTemplate)
rootCmd.SetFlagErrorFunc(FlagErrorFunc)
rootCmd.SetHelpCommand(helpCommand)
rootCmd.SetVersionTemplate("Docker version {{.Version}}\n")
rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")
@ -99,19 +99,9 @@ func managementSubCommands(cmd *cobra.Command) []*cobra.Command {
return cmds
}
// UseLine returns the usage line for a command. This implementation is different
// from the default Command.UseLine in that it does not add a `[flags]` to the
// end of the line.
func UseLine(cmd *cobra.Command) string {
if cmd.HasParent() {
return cmd.Parent().CommandPath() + " " + cmd.Use
}
return cmd.Use
}
var usageTemplate = `Usage:
{{- if not .HasSubCommands}} {{ useLine . }}{{end}}
{{- if not .HasSubCommands}} {{.UseLine}}{{end}}
{{- if .HasSubCommands}} {{ .CommandPath}} COMMAND{{end}}
{{ .Short | trim }}

View file

@ -9,6 +9,7 @@ BINARY_NATIVE_IMAGE_NAME = docker-cli-native$(IMAGE_TAG)
LINTER_IMAGE_NAME = docker-cli-lint$(IMAGE_TAG)
CROSS_IMAGE_NAME = docker-cli-cross$(IMAGE_TAG)
VALIDATE_IMAGE_NAME = docker-cli-shell-validate$(IMAGE_TAG)
E2E_IMAGE_NAME = docker-cli-e2e$(IMAGE_TAG)
MOUNTS = -v "$(CURDIR)":/go/src/github.com/docker/cli
VERSION = $(shell cat VERSION)
ENVVARS = -e VERSION=$(VERSION) -e GITCOMMIT -e PLATFORM
@ -35,6 +36,10 @@ build_shell_validate_image:
build_binary_native_image:
docker build -t $(BINARY_NATIVE_IMAGE_NAME) -f ./dockerfiles/Dockerfile.binary-native .
.PHONY: build_e2e_image
build_e2e_image:
docker build -t $(E2E_IMAGE_NAME) --build-arg VERSION=$(VERSION) --build-arg GITCOMMIT=$(GITCOMMIT) -f ./dockerfiles/Dockerfile.e2e .
# build executable using a container
binary: build_binary_native_image
@ -114,5 +119,5 @@ shellcheck: build_shell_validate_image
docker run -ti --rm $(ENVVARS) $(MOUNTS) $(VALIDATE_IMAGE_NAME) make shellcheck
.PHONY: test-e2e
test-e2e: binary
./scripts/test/e2e/wrapper
test-e2e: build_e2e_image
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock $(E2E_IMAGE_NAME)

View file

@ -1,19 +1,21 @@
github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
github.com/containerd/continuity d8fb8589b0e8e85b8c8bbaa8840226d0dfeb7371
github.com/coreos/etcd v3.2.1
github.com/cpuguy83/go-md2man v1.0.8
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
github.com/docker/docker ed7b6428c133e7c59404251a09b7d6b02fa83cc2
github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5
github.com/docker/docker d37f5c6bdf788a6cb82c07fb707e31a240eff5f9
github.com/docker/docker-credential-helpers 3c90bd29a46b943b2a9842987b58fb91a7c1819b
# the docker/go package contains a customized version of canonical/json
# and is used by Notary. The package is periodically rebased on current Go versions.
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
github.com/docker/swarmkit 49a9d7f6ba3c1925262641e694c18eb43575f74b
github.com/docker/swarmkit bd69f6e8e301645afd344913fa1ede53a0a111fb
github.com/emicklei/go-restful ff4f55a206334ef123e4f79bbf348980da81ca46
github.com/emicklei/go-restful-swagger12 dcef7f55730566d41eae5db10e7d6981829720f6
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
@ -34,6 +36,7 @@ github.com/go-openapi/spec 6aced65f8501fe1217321abf0749d354824ba2ff
github.com/go-openapi/swag 1d0bd113de87027671077d3c71eb3ac5d7dbba72
github.com/gregjones/httpcache c1f8028e62adb3d518b823a2f8e6a95c38bdd3aa
github.com/grpc-ecosystem/grpc-gateway 1a03ca3bad1e1ebadaedd3abb76bc58d4ac8143b
github.com/hashicorp/golang-lru 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
github.com/howeyc/gopass 3ca23474a7c7203e0a0a070fd33508f6efdb9b3d
github.com/imdario/mergo 9d5f1277e9a8ed20c3684bda8fde67c05628518c # v0.3.4
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
@ -41,10 +44,12 @@ github.com/juju/ratelimit 5b9ff866471762aa2ab2dced63c9fb6f53921342
github.com/json-iterator/go 6240e1e7983a85228f7fd9c3e1b6932d46ec58e2
github.com/mailru/easyjson d5b7844b561a7bc640052f1b935f7b800330d7e0
github.com/mattn/go-shellwords v1.0.3
github.com/matttproud/golang_protobuf_extensions v1.0.0
github.com/Microsoft/go-winio v0.4.6
github.com/miekg/pkcs11 5f6e0d0dad6f472df908c8e968a98ef00c9224bb
github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715
github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448
github.com/opencontainers/image-spec v1.0.1
@ -52,20 +57,24 @@ github.com/opencontainers/runc 4fc53a81fb7c994640722ac585fa9ca548971871
github.com/peterbourgon/diskv 5f041e8faa004a95c88a202771f4cc3e991971e6
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
github.com/pmezard/go-difflib v1.0.0
github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8
github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
github.com/PuerkitoBio/purell 8a290539e2e8629dbc4e6bad948158f790ec31f4
github.com/PuerkitoBio/urlesc 5bd2802263f21d8788851d5305584c82a5c75d7e
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
github.com/sirupsen/logrus v1.0.3
github.com/spf13/cobra 34ceca591bcf34a17a8b7bad5b3ce5f9c165bee5
github.com/spf13/pflag 97afa5e7ca8a08a383cb259e06636b5e2cc7897f
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.1
github.com/theupdateframework/notary v0.6.1
github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
golang.org/x/net a8b9294777976932365dabb6640cf1468d95c70f
golang.org/x/net 5561cd9b4330353950f399814f427425c0a26fd2
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
@ -79,5 +88,4 @@ k8s.io/apimachinery kubernetes-1.8.2
k8s.io/client-go kubernetes-1.8.2
k8s.io/kubernetes v1.8.2
k8s.io/kube-openapi 61b46af70dfed79c6d24530cd23b41440a7f22a5
vbom.ml/util 928aaa586d7718c70f4090ddf83f2b34c16fdc8d
github.com/hashicorp/golang-lru 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
vbom.ml/util 928aaa586d7718c70f4090ddf83f2b34c16fdc8d

View file

@ -13,8 +13,9 @@ Abhinandan Prativadi <abhi@docker.com>
Adrien Gallouët <adrien@gallouet.fr> <angt@users.noreply.github.com>
Ahmed Kamal <email.ahmedkamal@googlemail.com>
Ahmet Alp Balkan <ahmetb@microsoft.com> <ahmetalpbalkan@gmail.com>
AJ Bowen <aj@gandi.net>
AJ Bowen <aj@gandi.net> <amy@gandi.net>
AJ Bowen <aj@soulshake.net>
AJ Bowen <aj@soulshake.net> <aj@gandi.net>
AJ Bowen <aj@soulshake.net> <amy@gandi.net>
Akihiro Matsushima <amatsusbit@gmail.com> <amatsus@users.noreply.github.com>
Akihiro Suda <suda.akihiro@lab.ntt.co.jp> <suda.kyoto@gmail.com>
Aleksa Sarai <asarai@suse.de>
@ -24,6 +25,7 @@ Aleksandrs Fadins <aleks@s-ko.net>
Alessandro Boch <aboch@tetrationanalytics.com> <aboch@docker.com>
Alex Chen <alexchenunix@gmail.com> <root@localhost.localdomain>
Alex Ellis <alexellis2@gmail.com>
Alex Goodman <wagoodman@gmail.com> <wagoodman@users.noreply.github.com>
Alexander Larsson <alexl@redhat.com> <alexander.larsson@gmail.com>
Alexander Morozov <lk4d4@docker.com>
Alexander Morozov <lk4d4@docker.com> <lk4d4math@gmail.com>
@ -121,6 +123,7 @@ Doug Davis <dug@us.ibm.com> <duglin@users.noreply.github.com>
Doug Tangren <d.tangren@gmail.com>
Elan Ruusamäe <glen@pld-linux.org>
Elan Ruusamäe <glen@pld-linux.org> <glen@delfi.ee>
Elango Sivanandam <elango.siva@docker.com>
Eric G. Noriega <enoriega@vizuri.com> <egnoriega@users.noreply.github.com>
Eric Hanchrow <ehanchrow@ine.com> <eric.hanchrow@gmail.com>
Eric Rosenberg <ehaydenr@gmail.com> <ehaydenr@users.noreply.github.com>
@ -128,12 +131,14 @@ Erica Windisch <erica@windisch.us> <eric@windisch.us>
Erica Windisch <erica@windisch.us> <ewindisch@docker.com>
Erik Hollensbe <github@hollensbe.org> <erik+github@hollensbe.org>
Erwin van der Koogh <info@erronis.nl>
Ethan Bell <ebgamer29@gmail.com>
Euan Kemp <euan.kemp@coreos.com> <euank@amazon.com>
Eugen Krizo <eugen.krizo@gmail.com>
Evan Hazlett <ejhazlett@gmail.com> <ehazlett@users.noreply.github.com>
Evelyn Xu <evelynhsu21@gmail.com>
Evgeny Shmarnev <shmarnev@gmail.com>
Faiz Khan <faizkhan00@gmail.com>
Fangming Fang <fangming.fang@arm.com>
Felix Hupfeld <felix@quobyte.com> <quofelix@users.noreply.github.com>
Felix Ruess <felix.ruess@gmail.com> <felix.ruess@roboception.de>
Feng Yan <fy2462@gmail.com>
@ -155,6 +160,7 @@ Guillaume J. Charmes <guillaume.charmes@docker.com> <guillaume.charmes@dotcloud.
Guillaume J. Charmes <guillaume.charmes@docker.com> <guillaume@charmes.net>
Guillaume J. Charmes <guillaume.charmes@docker.com> <guillaume@docker.com>
Guillaume J. Charmes <guillaume.charmes@docker.com> <guillaume@dotcloud.com>
Guri <odg0318@gmail.com>
Gurjeet Singh <gurjeet@singh.im> <singh.gurjeet@gmail.com>
Gustav Sinder <gustav.sinder@gmail.com>
Günther Jungbluth <gunther@gameslabs.net>
@ -211,6 +217,8 @@ John Howard (VM) <John.Howard@microsoft.com> <jhoward@ntdev.microsoft.com>
John Howard (VM) <John.Howard@microsoft.com> <jhowardmsft@users.noreply.github.com>
John Howard (VM) <John.Howard@microsoft.com> <john.howard@microsoft.com>
John Stephens <johnstep@docker.com> <johnstep@users.noreply.github.com>
Jonathan Choy <jonathan.j.choy@gmail.com>
Jonathan Choy <jonathan.j.choy@gmail.com> <oni@tetsujinlabs.com>
Jon Surrell <jon.surrell@gmail.com> <jon.surrell@automattic.com>
Jordan Arentsen <blissdev@gmail.com>
Jordan Jennings <jjn2009@gmail.com> <jjn2009@users.noreply.github.com>
@ -286,6 +294,7 @@ Martin Redmond <redmond.martin@gmail.com> <xgithub@redmond5.com>
Mary Anthony <mary.anthony@docker.com> <mary@docker.com>
Mary Anthony <mary.anthony@docker.com> <moxieandmore@gmail.com>
Mary Anthony <mary.anthony@docker.com> moxiegirl <mary@docker.com>
Masato Ohba <over.rye@gmail.com>
Matt Bentley <matt.bentley@docker.com> <mbentley@mbentley.net>
Matt Schurenko <matt.schurenko@gmail.com>
Matt Williams <mattyw@me.com>
@ -298,9 +307,12 @@ Mauricio Garavaglia <mauricio@medallia.com> <mauriciogaravaglia@gmail.com>
Michael Crosby <michael@docker.com> <crosby.michael@gmail.com>
Michael Crosby <michael@docker.com> <crosbymichael@gmail.com>
Michael Crosby <michael@docker.com> <michael@crosbymichael.com>
Michał Gryko <github@odkurzacz.org>
Michael Hudson-Doyle <michael.hudson@canonical.com> <michael.hudson@linaro.org>
Michael Huettermann <michael@huettermann.net>
Michael Käufl <docker@c.michael-kaeufl.de> <michael-k@users.noreply.github.com>
Michael Nussbaum <michael.nussbaum@getbraintree.com>
Michael Nussbaum <michael.nussbaum@getbraintree.com> <code@getbraintree.com>
Michael Spetsiotis <michael_spets@hotmail.com>
Michal Minář <miminar@redhat.com>
Miguel Angel Alvarez Cabrerizo <doncicuto@gmail.com> <30386061+doncicuto@users.noreply.github.com>

View file

@ -39,7 +39,7 @@ Ahmed Kamal <email.ahmedkamal@googlemail.com>
Ahmet Alp Balkan <ahmetb@microsoft.com>
Aidan Feldman <aidan.feldman@gmail.com>
Aidan Hobson Sayers <aidanhs@cantab.net>
AJ Bowen <aj@gandi.net>
AJ Bowen <aj@soulshake.net>
Ajey Charantimath <ajey.charantimath@gmail.com>
ajneu <ajneu@users.noreply.github.com>
Akash Gupta <akagup@microsoft.com>
@ -54,6 +54,7 @@ Alan Scherger <flyinprogrammer@gmail.com>
Alan Thompson <cloojure@gmail.com>
Albert Callarisa <shark234@gmail.com>
Albert Zhang <zhgwenming@gmail.com>
Alejandro González Hevia <alejandrgh11@gmail.com>
Aleksa Sarai <asarai@suse.de>
Aleksandrs Fadins <aleks@s-ko.net>
Alena Prokharchyk <alena@rancher.com>
@ -65,6 +66,7 @@ Alex Coventry <alx@empirical.com>
Alex Crawford <alex.crawford@coreos.com>
Alex Ellis <alexellis2@gmail.com>
Alex Gaynor <alex.gaynor@gmail.com>
Alex Goodman <wagoodman@gmail.com>
Alex Olshansky <i@creagenics.com>
Alex Samorukov <samm@os2.kiev.ua>
Alex Warhawk <ax.warhawk@gmail.com>
@ -77,6 +79,7 @@ Alexander Shopov <ash@kambanaria.org>
Alexandre Beslic <alexandre.beslic@gmail.com>
Alexandre Garnier <zigarn@gmail.com>
Alexandre González <agonzalezro@gmail.com>
Alexandre Jomin <alexandrejomin@gmail.com>
Alexandru Sfirlogea <alexandru.sfirlogea@gmail.com>
Alexey Guskov <lexag@mail.ru>
Alexey Kotlyarov <alexey@infoxchange.net.au>
@ -98,11 +101,13 @@ Amir Goldstein <amir73il@aquasec.com>
Amit Bakshi <ambakshi@gmail.com>
Amit Krishnan <amit.krishnan@oracle.com>
Amit Shukla <amit.shukla@docker.com>
Amr Gawish <amr.gawish@gmail.com>
Amy Lindburg <amy.lindburg@docker.com>
Anand Patil <anand.prabhakar.patil@gmail.com>
AnandkumarPatel <anandkumarpatel@gmail.com>
Anatoly Borodin <anatoly.borodin@gmail.com>
Anchal Agrawal <aagrawa4@illinois.edu>
Anda Xu <anda.xu@docker.com>
Anders Janmyr <anders@janmyr.com>
Andre Dublin <81dublin@gmail.com>
Andre Granovsky <robotciti@live.com>
@ -197,6 +202,7 @@ Ben Toews <mastahyeti@gmail.com>
Ben Wiklund <ben@daisyowl.com>
Benjamin Atkin <ben@benatkin.com>
Benjamin Boudreau <boudreau.benjamin@gmail.com>
Benjamin Yolken <yolken@stripe.com>
Benoit Chesneau <bchesneau@gmail.com>
Bernerd Schaefer <bj.schaefer@gmail.com>
Bernhard M. Wiedemann <bwiedemann@suse.de>
@ -267,6 +273,7 @@ Carlos Sanchez <carlos@apache.org>
Carol Fager-Higgins <carol.fager-higgins@docker.com>
Cary <caryhartline@users.noreply.github.com>
Casey Bisson <casey.bisson@joyent.com>
Catalin Pirvu <pirvu.catalin94@gmail.com>
Ce Gao <ce.gao@outlook.com>
Cedric Davies <cedricda@microsoft.com>
Cezar Sa Espinola <cezarsa@gmail.com>
@ -293,6 +300,8 @@ Chen Min <chenmin46@huawei.com>
Chen Mingjie <chenmingjie0828@163.com>
Chen Qiu <cheney-90@hotmail.com>
Cheng-mean Liu <soccerl@microsoft.com>
Chengguang Xu <cgxu519@gmx.com>
chenyuzhu <chenyuzhi@oschina.cn>
Chetan Birajdar <birajdar.chetan@gmail.com>
Chewey <prosto-chewey@users.noreply.github.com>
Chia-liang Kao <clkao@clkao.org>
@ -313,6 +322,7 @@ Chris Snow <chsnow123@gmail.com>
Chris St. Pierre <chris.a.st.pierre@gmail.com>
Chris Stivers <chris@stivers.us>
Chris Swan <chris.swan@iee.org>
Chris Telfer <ctelfer@docker.com>
Chris Wahl <github@wahlnetwork.com>
Chris Weyl <cweyl@alumni.drew.edu>
Christian Berendt <berendt@b1-systems.de>
@ -336,6 +346,7 @@ Chun Chen <ramichen@tencent.com>
Ciro S. Costa <ciro.costa@usp.br>
Clayton Coleman <ccoleman@redhat.com>
Clinton Kitson <clintonskitson@gmail.com>
Cody Roseborough <crrosebo@amazon.com>
Coenraad Loubser <coenraad@wish.org.za>
Colin Dunklau <colin.dunklau@gmail.com>
Colin Hebert <hebert.colin@gmail.com>
@ -411,6 +422,7 @@ Dave MacDonald <mindlapse@gmail.com>
Dave Tucker <dt@docker.com>
David Anderson <dave@natulte.net>
David Calavera <david.calavera@gmail.com>
David Chung <david.chung@docker.com>
David Corking <dmc-source@dcorking.com>
David Cramer <davcrame@cisco.com>
David Currie <david_currie@uk.ibm.com>
@ -510,6 +522,7 @@ Eike Herzbach <eike@herzbach.net>
Eivin Giske Skaaren <eivinsn@axis.com>
Eivind Uggedal <eivind@uggedal.com>
Elan Ruusamäe <glen@pld-linux.org>
Elango Sivanandam <elango.siva@docker.com>
Elena Morozova <lelenanam@gmail.com>
Eli Uriegas <eli.uriegas@docker.com>
Elias Faxö <elias.faxo@tre.se>
@ -548,6 +561,7 @@ Erik St. Martin <alakriti@gmail.com>
Erik Weathers <erikdw@gmail.com>
Erno Hopearuoho <erno.hopearuoho@gmail.com>
Erwin van der Koogh <info@erronis.nl>
Ethan Bell <ebgamer29@gmail.com>
Euan Kemp <euan.kemp@coreos.com>
Eugen Krizo <eugen.krizo@gmail.com>
Eugene Yakubovich <eugene.yakubovich@coreos.com>
@ -575,6 +589,7 @@ Fabrizio Regini <freegenie@gmail.com>
Fabrizio Soppelsa <fsoppelsa@mirantis.com>
Faiz Khan <faizkhan00@gmail.com>
falmp <chico.lopes@gmail.com>
Fangming Fang <fangming.fang@arm.com>
Fangyuan Gao <21551127@zju.edu.cn>
Fareed Dudhia <fareeddudhia@googlemail.com>
Fathi Boudra <fathi.boudra@linaro.org>
@ -673,6 +688,7 @@ Guilherme Salgado <gsalgado@gmail.com>
Guillaume Dufour <gdufour.prestataire@voyages-sncf.com>
Guillaume J. Charmes <guillaume.charmes@docker.com>
guoxiuyan <guoxiuyan@huawei.com>
Guri <odg0318@gmail.com>
Gurjeet Singh <gurjeet@singh.im>
Guruprasad <lgp171188@gmail.com>
Gustav Sinder <gustav.sinder@gmail.com>
@ -696,6 +712,7 @@ heartlock <21521209@zju.edu.cn>
Hector Castro <hectcastro@gmail.com>
Helen Xie <chenjg@harmonycloud.cn>
Henning Sprang <henning.sprang@gmail.com>
Hiroshi Hatake <hatake@clear-code.com>
Hobofan <goisser94@gmail.com>
Hollie Teal <hollie@docker.com>
Hong Xu <hong@topbug.net>
@ -808,6 +825,7 @@ Jean-Pierre Huynh <jean-pierre.huynh@ounet.fr>
Jean-Tiare Le Bigot <jt@yadutaf.fr>
Jeeva S. Chelladhurai <sjeeva@gmail.com>
Jeff Anderson <jeff@docker.com>
Jeff Hajewski <jeff.hajewski@gmail.com>
Jeff Johnston <jeff.johnston.mn@gmail.com>
Jeff Lindsay <progrium@gmail.com>
Jeff Mickey <j@codemac.net>
@ -893,6 +911,7 @@ Jonas Pfenniger <jonas@pfenniger.name>
Jonathan A. Sternberg <jonathansternberg@gmail.com>
Jonathan Boulle <jonathanboulle@gmail.com>
Jonathan Camp <jonathan@irondojo.com>
Jonathan Choy <jonathan.j.choy@gmail.com>
Jonathan Dowland <jon+github@alcopop.org>
Jonathan Lebon <jlebon@redhat.com>
Jonathan Lomas <jonathan@floatinglomas.ca>
@ -962,6 +981,7 @@ Kareem Khazem <karkhaz@karkhaz.com>
kargakis <kargakis@users.noreply.github.com>
Karl Grzeszczak <karlgrz@gmail.com>
Karol Duleba <mr.fuxi@gmail.com>
Karthik Karanth <karanth.karthik@gmail.com>
Karthik Nayak <Karthik.188@gmail.com>
Kate Heddleston <kate.heddleston@gmail.com>
Katie McLaughlin <katie@glasnt.com>
@ -1108,6 +1128,7 @@ Manfred Zabarauskas <manfredas@zabarauskas.com>
Manjunath A Kumatagi <mkumatag@in.ibm.com>
Mansi Nahar <mmn4185@rit.edu>
Manuel Meurer <manuel@krautcomputing.com>
Manuel Rüger <manuel@rueg.eu>
Manuel Woelker <github@manuel.woelker.org>
mapk0y <mapk0y@gmail.com>
Marc Abramowitz <marc@marc-abramowitz.com>
@ -1149,10 +1170,12 @@ Martin Mosegaard Amdisen <martin.amdisen@praqma.com>
Martin Redmond <redmond.martin@gmail.com>
Mary Anthony <mary.anthony@docker.com>
Masahito Zembutsu <zembutsu@users.noreply.github.com>
Masato Ohba <over.rye@gmail.com>
Masayuki Morita <minamijoyo@gmail.com>
Mason Malone <mason.malone@gmail.com>
Mateusz Sulima <sulima.mateusz@gmail.com>
Mathias Monnerville <mathias@monnerville.com>
Mathieu Champlon <mathieu.champlon@docker.com>
Mathieu Le Marec - Pasquet <kiorky@cryptelium.net>
Mathieu Parent <math.parent@gmail.com>
Matt Apperson <me@mattapperson.com>
@ -1209,6 +1232,7 @@ Michael Huettermann <michael@huettermann.net>
Michael Irwin <mikesir87@gmail.com>
Michael Käufl <docker@c.michael-kaeufl.de>
Michael Neale <michael.neale@gmail.com>
Michael Nussbaum <michael.nussbaum@getbraintree.com>
Michael Prokop <github@michael-prokop.at>
Michael Scharf <github@scharf.gr>
Michael Spetsiotis <michael_spets@hotmail.com>
@ -1223,6 +1247,7 @@ Michal Minář <miminar@redhat.com>
Michal Wieczorek <wieczorek-michal@wp.pl>
Michaël Pailloncy <mpapo.dev@gmail.com>
Michał Czeraszkiewicz <czerasz@gmail.com>
Michał Gryko <github@odkurzacz.org>
Michiel@unhosted <michiel@unhosted.org>
Mickaël FORTUNATO <morsi.morsicus@gmail.com>
Miguel Angel Fernández <elmendalerenda@gmail.com>
@ -1239,6 +1264,7 @@ Mike Estes <mike.estes@logos.com>
Mike Gaffney <mike@uberu.com>
Mike Goelzer <mike.goelzer@docker.com>
Mike Leone <mleone896@gmail.com>
Mike Lundy <mike@fluffypenguin.org>
Mike MacCana <mike.maccana@gmail.com>
Mike Naberezny <mike@naberezny.com>
Mike Snitzer <snitzer@redhat.com>
@ -1297,6 +1323,7 @@ Niall O'Higgins <niallo@unworkable.org>
Nicholas E. Rabenau <nerab@gmx.at>
Nick DeCoursin <n.decoursin@foodpanda.com>
Nick Irvine <nfirvine@nfirvine.com>
Nick Neisen <nwneisen@gmail.com>
Nick Parker <nikaios@gmail.com>
Nick Payne <nick@kurai.co.uk>
Nick Russo <nicholasjamesrusso@gmail.com>
@ -1322,6 +1349,7 @@ Nishant Totla <nishanttotla@gmail.com>
NIWA Hideyuki <niwa.niwa@nifty.ne.jp>
Noah Meyerhans <nmeyerha@amazon.com>
Noah Treuhaft <noah.treuhaft@docker.com>
NobodyOnSE <ich@sektor.selfip.com>
noducks <onemannoducks@gmail.com>
Nolan Darilek <nolan@thewordnerd.info>
nponeccop <andy.melnikov@gmail.com>
@ -1329,7 +1357,6 @@ Nuutti Kotivuori <naked@iki.fi>
nzwsch <hi@nzwsch.com>
O.S. Tezer <ostezer@gmail.com>
objectified <objectified@gmail.com>
odk- <github@odkurzacz.org>
Oguz Bilgic <fisyonet@gmail.com>
Oh Jinkyun <tintypemolly@gmail.com>
Ohad Schneider <ohadschn@users.noreply.github.com>
@ -1352,6 +1379,7 @@ Patrick Böänziger <patrick.baenziger@bsi-software.com>
Patrick Devine <patrick.devine@docker.com>
Patrick Hemmer <patrick.hemmer@gmail.com>
Patrick Stapleton <github@gdi2290.com>
Patrik Cyvoct <patrik@ptrk.io>
pattichen <craftsbear@gmail.com>
Paul <paul9869@gmail.com>
paul <paul@inkling.com>
@ -1423,6 +1451,7 @@ Pradip Dhara <pradipd@microsoft.com>
Prasanna Gautam <prasannagautam@gmail.com>
Pratik Karki <prertik@outlook.com>
Prayag Verma <prayag.verma@gmail.com>
Priya Wadhwa <priyawadhwa@google.com>
Przemek Hejman <przemyslaw.hejman@gmail.com>
Pure White <daniel48@126.com>
pysqz <randomq@126.com>
@ -1838,11 +1867,13 @@ Wang Xing <hzwangxing@corp.netease.com>
Wang Yuexiao <wang.yuexiao@zte.com.cn>
Ward Vandewege <ward@jhvc.com>
WarheadsSE <max@warheads.net>
Wassim Dhif <wassimdhif@gmail.com>
Wayne Chang <wayne@neverfear.org>
Wayne Song <wsong@docker.com>
Weerasak Chongnguluam <singpor@gmail.com>
Wei Wu <wuwei4455@gmail.com>
Wei-Ting Kuo <waitingkuo0527@gmail.com>
weipeng <weipeng@tuscloud.io>
weiyan <weiyan3@huawei.com>
Weiyang Zhu <cnresonant@gmail.com>
Wen Cheng Ma <wenchma@cn.ibm.com>
@ -1948,5 +1979,6 @@ Zunayed Ali <zunayed@gmail.com>
Átila Camurça Alves <camurca.home@gmail.com>
尹吉峰 <jifeng.yin@gmail.com>
徐俊杰 <paco.xu@daocloud.io>
慕陶 <jihui.xjh@alibaba-inc.com>
搏通 <yufeng.pyf@alibaba-inc.com>
黄艳红00139573 <huang.yanhong@zte.com.cn>

View file

@ -5,6 +5,28 @@ information on the list of deprecated flags and APIs please have a look at
https://docs.docker.com/engine/deprecated/ where target removal dates can also
be found.
## 17.03.2-ce (2017-05-29)
### Networking
- Fix a concurrency issue preventing network creation [#33273](https://github.com/moby/moby/pull/33273)
### Runtime
- Relabel secrets path to avoid a Permission Denied on selinux enabled systems [#33236](https://github.com/moby/moby/pull/33236) (ref [#32529](https://github.com/moby/moby/pull/32529)
- Fix cases where local volume were not properly relabeled if needed [#33236](https://github.com/moby/moby/pull/33236) (ref [#29428](https://github.com/moby/moby/pull/29428))
- Fix an issue while upgrading if a plugin rootfs was still mounted [#33236](https://github.com/moby/moby/pull/33236) (ref [#32525](https://github.com/moby/moby/pull/32525))
- Fix an issue where volume wouldn't default to the `rprivate` propagation mode [#33236](https://github.com/moby/moby/pull/33236) (ref [#32851](https://github.com/moby/moby/pull/32851))
- Fix a panic that could occur when a volume driver could not be retrieved [#33236](https://github.com/moby/moby/pull/33236) (ref [#32347](https://github.com/moby/moby/pull/32347))
+ Add a warning in `docker info` when the `overlay` or `overlay2` graphdriver is used on a filesystem without `d_type` support [#33236](https://github.com/moby/moby/pull/33236) (ref [#31290](https://github.com/moby/moby/pull/31290))
- Fix an issue with backporting mount spec to older volumes [#33207](https://github.com/moby/moby/pull/33207)
- Fix issue where a failed unmount can lead to data loss on local volume remove [#33120](https://github.com/moby/moby/pull/33120)
### Swarm Mode
- Fix a case where tasks could get killed unexpectedly [#33118](https://github.com/moby/moby/pull/33118)
- Fix an issue preventing to deploy services if the registry cannot be reached despite the needed images being locally present [#33117](https://github.com/moby/moby/pull/33117)
## 17.05.0-ce (2017-05-04)
### Builder
@ -176,28 +198,6 @@ be found.
* Block pulling Windows images on non-Windows daemons [#29001](https://github.com/docker/docker/pull/29001)
## 17.03.2-ce (2017-05-29)
### Networking
- Fix a concurrency issue preventing network creation [#33273](https://github.com/moby/moby/pull/33273)
### Runtime
- Relabel secrets path to avoid a Permission Denied on selinux enabled systems [#33236](https://github.com/moby/moby/pull/33236) (ref [#32529](https://github.com/moby/moby/pull/32529)
- Fix cases where local volume were not properly relabeled if needed [#33236](https://github.com/moby/moby/pull/33236) (ref [#29428](https://github.com/moby/moby/pull/29428))
- Fix an issue while upgrading if a plugin rootfs was still mounted [#33236](https://github.com/moby/moby/pull/33236) (ref [#32525](https://github.com/moby/moby/pull/32525))
- Fix an issue where volume wouldn't default to the `rprivate` propagation mode [#33236](https://github.com/moby/moby/pull/33236) (ref [#32851](https://github.com/moby/moby/pull/32851))
- Fix a panic that could occur when a volume driver could not be retrieved [#33236](https://github.com/moby/moby/pull/33236) (ref [#32347](https://github.com/moby/moby/pull/32347))
+ Add a warning in `docker info` when the `overlay` or `overlay2` graphdriver is used on a filesystem without `d_type` support [#33236](https://github.com/moby/moby/pull/33236) (ref [#31290](https://github.com/moby/moby/pull/31290))
- Fix an issue with backporting mount spec to older volumes [#33207](https://github.com/moby/moby/pull/33207)
- Fix issue where a failed unmount can lead to data loss on local volume remove [#33120](https://github.com/moby/moby/pull/33120)
### Swarm Mode
- Fix a case where tasks could get killed unexpectedly [#33118](https://github.com/moby/moby/pull/33118)
- Fix an issue preventing to deploy services if the registry cannot be reached despite the needed images being locally present [#33117](https://github.com/moby/moby/pull/33117)
## 17.03.1-ce (2017-03-27)
### Remote API (v1.27) & Client

View file

@ -20,14 +20,6 @@
# # Run tests e.g. integration, py
# # hack/make.sh binary test-integration test-docker-py
#
# # Publish a release:
# docker run --privileged \
# -e AWS_S3_BUCKET=baz \
# -e AWS_ACCESS_KEY=foo \
# -e AWS_SECRET_KEY=bar \
# -e GPG_PASSPHRASE=gloubiboulga \
# docker hack/release.sh
#
# Note: AppArmor used to mess with privileged mode, but this is no longer
# the case. Therefore, you don't have to disable it anymore.
#

View file

@ -43,6 +43,7 @@ DOCKER_ENVS := \
-e DOCKER_REMAP_ROOT \
-e DOCKER_STORAGE_OPTS \
-e DOCKER_USERLANDPROXY \
-e DOCKERD_ARGS \
-e TEST_INTEGRATION_DIR \
-e TESTDIRS \
-e TESTFLAGS \

View file

@ -3,9 +3,9 @@ package api // import "github.com/docker/docker/api"
// Common constants for daemon and client.
const (
// DefaultVersion of Current REST API
DefaultVersion string = "1.37"
DefaultVersion = "1.38"
// NoBaseImageSpecifier is the symbol used by the FROM
// command to specify that no base image is to be used.
NoBaseImageSpecifier string = "scratch"
NoBaseImageSpecifier = "scratch"
)

View file

@ -3,4 +3,4 @@
package api // import "github.com/docker/docker/api"
// MinVersion represents Minimum REST API version supported
const MinVersion string = "1.12"
const MinVersion = "1.12"

View file

@ -19,10 +19,10 @@ produces:
consumes:
- "application/json"
- "text/plain"
basePath: "/v1.37"
basePath: "/v1.38"
info:
title: "Docker Engine API"
version: "1.37"
version: "1.38"
x-logo:
url: "https://docs.docker.com/images/logo-docker-main.png"
description: |
@ -49,8 +49,8 @@ info:
the URL is not supported by the daemon, a HTTP `400 Bad Request` error message
is returned.
If you omit the version-prefix, the current version of the API (v1.37) is used.
For example, calling `/info` is the same as calling `/v1.37/info`. Using the
If you omit the version-prefix, the current version of the API (v1.38) is used.
For example, calling `/info` is the same as calling `/v1.38/info`. Using the
API without a version-prefix is deprecated and will be removed in a future release.
Engine releases in the near future should support this version of the API,
@ -155,6 +155,7 @@ definitions:
IP:
type: "string"
format: "ip-address"
description: "Host IP address that the container's port is mapped to"
PrivatePort:
type: "integer"
format: "uint16"
@ -1858,6 +1859,13 @@ definitions:
type: "string"
x-nullable: false
example: "plugins.sock"
ProtocolScheme:
type: "string"
example: "some.protocol/v1.0"
description: "Protocol to use for clients connecting to the plugin."
enum:
- ""
- "moby.plugins.http/v1"
Entrypoint:
type: "array"
items:
@ -2448,7 +2456,15 @@ definitions:
properties:
PluginSpec:
type: "object"
description: "Invalid when specified with `ContainerSpec`. *(Experimental release only.)*"
description: |
Plugin spec for the service. *(Experimental release only.)*
<p><br /></p>
> **Note**: ContainerSpec, NetworkAttachmentSpec, and PluginSpec are
> mutually exclusive. PluginSpec is only used when the Runtime field
> is set to `plugin`. NetworkAttachmentSpec is used when the Runtime
> field is set to `attachment`.
properties:
Name:
description: "The name or 'alias' to use for the plugin."
@ -2475,7 +2491,15 @@ definitions:
type: "string"
ContainerSpec:
type: "object"
description: "Invalid when specified with `PluginSpec`."
description: |
Container spec for the service.
<p><br /></p>
> **Note**: ContainerSpec, NetworkAttachmentSpec, and PluginSpec are
> mutually exclusive. PluginSpec is only used when the Runtime field
> is set to `plugin`. NetworkAttachmentSpec is used when the Runtime
> field is set to `attachment`.
properties:
Image:
description: "The image name to use for the container"
@ -2687,6 +2711,22 @@ definitions:
- "default"
- "process"
- "hyperv"
NetworkAttachmentSpec:
description: |
Read-only spec type for non-swarm containers attached to swarm overlay
networks.
<p><br /></p>
> **Note**: ContainerSpec, NetworkAttachmentSpec, and PluginSpec are
> mutually exclusive. PluginSpec is only used when the Runtime field
> is set to `plugin`. NetworkAttachmentSpec is used when the Runtime
> field is set to `attachment`.
type: "object"
properties:
ContainerID:
description: "ID of the container represented by this task"
type: "string"
Resources:
description: "Resource requirements which apply to each individual container created as part of the service."
type: "object"
@ -3814,7 +3854,7 @@ definitions:
- "process"
InitBinary:
description: |
Name and, optional, path of the the `docker-init` binary.
Name and, optional, path of the `docker-init` binary.
If the path is omitted, the daemon searches the host's `$PATH` for the
binary and uses the first result.
@ -4032,7 +4072,7 @@ definitions:
- "https://registry-3.docker.io/"
Secure:
description: |
Indicates if the the registry is part of the list of insecure
Indicates if the registry is part of the list of insecure
registries.
If `false`, the registry is insecure. Insecure registries accept
@ -4662,7 +4702,11 @@ paths:
AppArmorProfile:
type: "string"
ExecIDs:
type: "string"
description: "IDs of exec instances that are running in the container."
type: "array"
items:
type: "string"
x-nullable: true
HostConfig:
$ref: "#/definitions/HostConfig"
GraphDriver:
@ -4719,6 +4763,9 @@ paths:
StopTimeout: 10
Created: "2015-01-06T15:47:31.485331387Z"
Driver: "devicemapper"
ExecIDs:
- "b35395de42bc8abd327f9dd65d913b9ba28c74d2f0734eeeae84fa1c616a0fca"
- "3fc1232e5cd20c8de182ed81178503dc6437f4e7ef12b52cc5e8de020652f1c4"
HostConfig:
MaximumIOps: 0
MaximumIOBps: 0
@ -5094,9 +5141,9 @@ paths:
This endpoint returns a live stream of a containers resource usage
statistics.
The `precpu_stats` is the CPU statistic of last read, which is used
for calculating the CPU usage percentage. It is not the same as the
`cpu_stats` field.
The `precpu_stats` is the CPU statistic of the *previous* read, and is
used to calculate the CPU usage percentage. It is not an exact copy
of the `cpu_stats` field.
If either `precpu_stats.online_cpus` or `cpu_stats.online_cpus` is
nil then for compatibility with older daemons the length of the

View file

@ -7,7 +7,7 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
units "github.com/docker/go-units"
"github.com/docker/go-units"
)
// CheckpointCreateOptions holds parameters to create a checkpoint from a container

View file

@ -121,6 +121,9 @@ type PluginConfigArgs struct {
// swagger:model PluginConfigInterface
type PluginConfigInterface struct {
// Protocol to use for clients connecting to the plugin.
ProtocolScheme string `json:"ProtocolScheme,omitempty"`
// socket
// Required: true
Socket string `json:"Socket"`

View file

@ -7,7 +7,7 @@ package types
// swagger:model Port
type Port struct {
// IP
// Host IP address that the container's port is mapped to
IP string `json:"IP,omitempty"`
// Port on the container

View file

@ -11,9 +11,17 @@ const (
RuntimeContainer RuntimeType = "container"
// RuntimePlugin is the plugin based runtime
RuntimePlugin RuntimeType = "plugin"
// RuntimeNetworkAttachment is the network attachment runtime
RuntimeNetworkAttachment RuntimeType = "attachment"
// RuntimeURLContainer is the proto url for the container type
RuntimeURLContainer RuntimeURL = "types.docker.com/RuntimeContainer"
// RuntimeURLPlugin is the proto url for the plugin type
RuntimeURLPlugin RuntimeURL = "types.docker.com/RuntimePlugin"
)
// NetworkAttachmentSpec represents the runtime spec type for network
// attachment tasks
type NetworkAttachmentSpec struct {
ContainerID string
}

View file

@ -60,10 +60,13 @@ type Task struct {
// TaskSpec represents the spec of a task.
type TaskSpec struct {
// ContainerSpec and PluginSpec are mutually exclusive.
// PluginSpec will only be used when the `Runtime` field is set to `plugin`
ContainerSpec *ContainerSpec `json:",omitempty"`
PluginSpec *runtime.PluginSpec `json:",omitempty"`
// ContainerSpec, NetworkAttachmentSpec, and PluginSpec are mutually exclusive.
// PluginSpec is only used when the `Runtime` field is set to `plugin`
// NetworkAttachmentSpec is used if the `Runtime` field is set to
// `attachment`.
ContainerSpec *ContainerSpec `json:",omitempty"`
PluginSpec *runtime.PluginSpec `json:",omitempty"`
NetworkAttachmentSpec *NetworkAttachmentSpec `json:",omitempty"`
Resources *ResourceRequirements `json:",omitempty"`
RestartPolicy *RestartPolicy `json:",omitempty"`

View file

@ -82,11 +82,14 @@ func GetTimestamp(value string, reference time.Time) (string, error) {
}
if err != nil {
// if there is a `-` then it's an RFC3339 like timestamp otherwise assume unixtimestamp
// if there is a `-` then it's an RFC3339 like timestamp
if strings.Contains(value, "-") {
return "", err // was probably an RFC3339 like timestamp but the parser failed with an error
}
return value, nil // unixtimestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server)
if _, _, err := parseTimestamp(value); err != nil {
return "", fmt.Errorf("failed to parse value as time or duration: %q", value)
}
return value, nil // unix timestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server)
}
return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil
@ -104,6 +107,10 @@ func ParseTimestamps(value string, def int64) (int64, int64, error) {
if value == "" {
return def, 0, nil
}
return parseTimestamp(value)
}
func parseTimestamp(value string) (int64, int64, error) {
sa := strings.SplitN(value, ".", 2)
s, err := strconv.ParseInt(sa[0], 10, 64)
if err != nil {

View file

@ -49,8 +49,8 @@ func TestGetTimestamp(t *testing.T) {
{"1.5h", fmt.Sprintf("%d", now.Add(-90*time.Minute).Unix()), false},
{"1h30m", fmt.Sprintf("%d", now.Add(-90*time.Minute).Unix()), false},
// String fallback
{"invalid", "invalid", false},
{"invalid", "", true},
{"", "", true},
}
for _, c := range cases {

View file

@ -1,4 +1,4 @@
package volume // import "github.com/docker/docker/api/types/volume"
package volume
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
@ -7,9 +7,9 @@ package volume // import "github.com/docker/docker/api/types/volume"
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
// VolumesCreateBody volumes create body
// swagger:model VolumesCreateBody
type VolumesCreateBody struct {
// VolumeCreateBody
// swagger:model VolumeCreateBody
type VolumeCreateBody struct {
// Name of the volume driver to use.
// Required: true

View file

@ -1,4 +1,4 @@
package volume // import "github.com/docker/docker/api/types/volume"
package volume
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
@ -9,9 +9,9 @@ package volume // import "github.com/docker/docker/api/types/volume"
import "github.com/docker/docker/api/types"
// VolumesListOKBody volumes list o k body
// swagger:model VolumesListOKBody
type VolumesListOKBody struct {
// VolumeListOKBody
// swagger:model VolumeListOKBody
type VolumeListOKBody struct {
// List of volumes
// Required: true

View file

@ -2,10 +2,8 @@ package cli // import "github.com/docker/docker/cli"
import (
"fmt"
"strings"
"github.com/docker/docker/pkg/term"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@ -21,7 +19,7 @@ func SetupRootCommand(rootCmd *cobra.Command) {
rootCmd.SetUsageTemplate(usageTemplate)
rootCmd.SetHelpTemplate(helpTemplate)
rootCmd.SetFlagErrorFunc(FlagErrorFunc)
rootCmd.SetHelpCommand(helpCommand)
rootCmd.SetVersionTemplate("Docker version {{.Version}}\n")
rootCmd.PersistentFlags().BoolP("help", "h", false, "Print usage")
rootCmd.PersistentFlags().MarkShorthandDeprecated("help", "please use --help")
@ -44,23 +42,6 @@ func FlagErrorFunc(cmd *cobra.Command, err error) error {
}
}
var helpCommand = &cobra.Command{
Use: "help [command]",
Short: "Help about the command",
PersistentPreRun: func(cmd *cobra.Command, args []string) {},
PersistentPostRun: func(cmd *cobra.Command, args []string) {},
RunE: func(c *cobra.Command, args []string) error {
cmd, args, e := c.Root().Find(args)
if cmd == nil || e != nil || len(args) > 0 {
return errors.Errorf("unknown help topic: %v", strings.Join(args, " "))
}
helpFunc := cmd.HelpFunc()
helpFunc(cmd, args)
return nil
},
}
func hasSubCommands(cmd *cobra.Command) bool {
return len(operationSubCommands(cmd)) > 0
}
@ -70,7 +51,7 @@ func hasManagementSubCommands(cmd *cobra.Command) bool {
}
func operationSubCommands(cmd *cobra.Command) []*cobra.Command {
cmds := []*cobra.Command{}
var cmds []*cobra.Command
for _, sub := range cmd.Commands() {
if sub.IsAvailableCommand() && !sub.HasSubCommands() {
cmds = append(cmds, sub)
@ -88,7 +69,7 @@ func wrappedFlagUsages(cmd *cobra.Command) string {
}
func managementSubCommands(cmd *cobra.Command) []*cobra.Command {
cmds := []*cobra.Command{}
var cmds []*cobra.Command
for _, sub := range cmd.Commands() {
if sub.IsAvailableCommand() && sub.HasSubCommands() {
cmds = append(cmds, sub)
@ -116,7 +97,7 @@ Examples:
{{ .Example }}
{{- end}}
{{- if .HasFlags}}
{{- if .HasAvailableFlags}}
Options:
{{ wrappedFlagUsages . | trimRightSpace}}

View file

@ -356,6 +356,11 @@ func (cli *Client) DaemonHost() string {
return cli.host
}
// HTTPClient returns a copy of the HTTP client bound to the server
func (cli *Client) HTTPClient() *http.Client {
return &*cli.client
}
// ParseHostURL parses a url string, validates the string is a host url, and
// returns the parsed URL
func ParseHostURL(host string) (*url.URL, error) {

View file

@ -10,7 +10,6 @@ import (
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/internal/testutil"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/env"
@ -162,7 +161,7 @@ func TestParseHostURL(t *testing.T) {
for _, testcase := range testcases {
actual, err := ParseHostURL(testcase.host)
if testcase.expectedErr != "" {
testutil.ErrorContains(t, err, testcase.expectedErr)
assert.Check(t, is.ErrorContains(err, testcase.expectedErr))
}
assert.Check(t, is.DeepEqual(testcase.expected, actual))
}

View file

@ -8,6 +8,7 @@ import (
"github.com/docker/docker/api/types"
timetypes "github.com/docker/docker/api/types/time"
"github.com/pkg/errors"
)
// ContainerLogs returns the logs generated by a container in an io.ReadCloser.
@ -45,7 +46,7 @@ func (cli *Client) ContainerLogs(ctx context.Context, container string, options
if options.Since != "" {
ts, err := timetypes.GetTimestamp(options.Since, time.Now())
if err != nil {
return nil, err
return nil, errors.Wrap(err, `invalid value for "since"`)
}
query.Set("since", ts)
}
@ -53,7 +54,7 @@ func (cli *Client) ContainerLogs(ctx context.Context, container string, options
if options.Until != "" {
ts, err := timetypes.GetTimestamp(options.Until, time.Now())
if err != nil {
return nil, err
return nil, errors.Wrap(err, `invalid value for "until"`)
}
query.Set("until", ts)
}

View file

@ -2,6 +2,7 @@ package client // import "github.com/docker/docker/client"
import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
@ -12,10 +13,9 @@ import (
"testing"
"time"
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/internal/testutil"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
)
func TestContainerLogsNotFoundError(t *testing.T) {
@ -33,17 +33,15 @@ func TestContainerLogsError(t *testing.T) {
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.ContainerLogs(context.Background(), "container_id", types.ContainerLogsOptions{})
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
assert.Check(t, is.Error(err, "Error response from daemon: Server error"))
_, err = client.ContainerLogs(context.Background(), "container_id", types.ContainerLogsOptions{
Since: "2006-01-02TZ",
})
testutil.ErrorContains(t, err, `parsing time "2006-01-02TZ"`)
assert.Check(t, is.ErrorContains(err, `parsing time "2006-01-02TZ"`))
_, err = client.ContainerLogs(context.Background(), "container_id", types.ContainerLogsOptions{
Until: "2006-01-02TZ",
})
testutil.ErrorContains(t, err, `parsing time "2006-01-02TZ"`)
assert.Check(t, is.ErrorContains(err, `parsing time "2006-01-02TZ"`))
}
func TestContainerLogs(t *testing.T) {
@ -51,6 +49,7 @@ func TestContainerLogs(t *testing.T) {
cases := []struct {
options types.ContainerLogsOptions
expectedQueryParams map[string]string
expectedError string
}{
{
expectedQueryParams: map[string]string{
@ -84,32 +83,44 @@ func TestContainerLogs(t *testing.T) {
},
{
options: types.ContainerLogsOptions{
// An complete invalid date, timestamp or go duration will be
// passed as is
Since: "invalid but valid",
// timestamp will be passed as is
Since: "1136073600.000000001",
},
expectedQueryParams: map[string]string{
"tail": "",
"since": "invalid but valid",
"since": "1136073600.000000001",
},
},
{
options: types.ContainerLogsOptions{
// An complete invalid date, timestamp or go duration will be
// passed as is
Until: "invalid but valid",
// timestamp will be passed as is
Until: "1136073600.000000001",
},
expectedQueryParams: map[string]string{
"tail": "",
"until": "invalid but valid",
"until": "1136073600.000000001",
},
},
{
options: types.ContainerLogsOptions{
// An complete invalid date will not be passed
Since: "invalid value",
},
expectedError: `invalid value for "since": failed to parse value as time or duration: "invalid value"`,
},
{
options: types.ContainerLogsOptions{
// An complete invalid date will not be passed
Until: "invalid value",
},
expectedError: `invalid value for "until": failed to parse value as time or duration: "invalid value"`,
},
}
for _, logCase := range cases {
client := &Client{
client: newMockClient(func(r *http.Request) (*http.Response, error) {
if !strings.HasPrefix(r.URL.Path, expectedURL) {
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, r.URL)
return nil, fmt.Errorf("expected URL '%s', got '%s'", expectedURL, r.URL)
}
// Check query parameters
query := r.URL.Query()
@ -126,17 +137,15 @@ func TestContainerLogs(t *testing.T) {
}),
}
body, err := client.ContainerLogs(context.Background(), "container_id", logCase.options)
if err != nil {
t.Fatal(err)
if logCase.expectedError != "" {
assert.Check(t, is.Error(err, logCase.expectedError))
continue
}
assert.NilError(t, err)
defer body.Close()
content, err := ioutil.ReadAll(body)
if err != nil {
t.Fatal(err)
}
if string(content) != "response" {
t.Fatalf("expected response to contain 'response', got %s", string(content))
}
assert.NilError(t, err)
assert.Check(t, is.Contains(string(content), "response"))
}
}

View file

@ -8,8 +8,13 @@ import (
timetypes "github.com/docker/docker/api/types/time"
)
// ContainerStop stops a container without terminating the process.
// The process is blocked until the container stops or the timeout expires.
// ContainerStop stops a container. In case the container fails to stop
// gracefully within a time frame specified by the timeout argument,
// it is forcefully terminated (killed).
//
// If the timeout is nil, the container's StopTimeout value is used, if set,
// otherwise the engine default. A negative timeout value can be specified,
// meaning no timeout, i.e. no forceful termination is performed.
func (cli *Client) ContainerStop(ctx context.Context, containerID string, timeout *time.Duration) error {
query := url.Values{}
if timeout != nil {

View file

@ -2,6 +2,7 @@ package client // import "github.com/docker/docker/client"
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
@ -11,8 +12,6 @@ import (
"testing"
"time"
"context"
"github.com/docker/docker/api/types/container"
)

View file

@ -2,7 +2,6 @@ package client // import "github.com/docker/docker/client"
import (
"fmt"
"net/http"
"github.com/docker/docker/api/types/versions"

View file

@ -7,9 +7,8 @@ import (
"io/ioutil"
"net/http"
"reflect"
"testing"
"strings"
"testing"
)
func TestImageSaveError(t *testing.T) {

View file

@ -4,6 +4,7 @@ import (
"context"
"io"
"net"
"net/http"
"time"
"github.com/docker/docker/api/types"
@ -33,6 +34,7 @@ type CommonAPIClient interface {
VolumeAPIClient
ClientVersion() string
DaemonHost() string
HTTPClient() *http.Client
ServerVersion(ctx context.Context) (types.Version, error)
NegotiateAPIVersion(ctx context.Context)
NegotiateAPIVersionPing(types.Ping)
@ -168,10 +170,10 @@ type SystemAPIClient interface {
// VolumeAPIClient defines API client methods for the volumes
type VolumeAPIClient interface {
VolumeCreate(ctx context.Context, options volumetypes.VolumesCreateBody) (types.Volume, error)
VolumeCreate(ctx context.Context, options volumetypes.VolumeCreateBody) (types.Volume, error)
VolumeInspect(ctx context.Context, volumeID string) (types.Volume, error)
VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error)
VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumesListOKBody, error)
VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumeListOKBody, error)
VolumeRemove(ctx context.Context, volumeID string, force bool) error
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (types.VolumesPruneReport, error)
}

View file

@ -1,9 +1,8 @@
package client // import "github.com/docker/docker/client"
import (
"net/url"
"context"
"net/url"
"github.com/docker/docker/api/types"
)

View file

@ -2,14 +2,13 @@ package client // import "github.com/docker/docker/client"
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"
"context"
"github.com/docker/docker/api/types"
)

View file

@ -14,7 +14,7 @@ import (
// TestPingFail tests that when a server sends a non-successful response that we
// can still grab API details, when set.
// Some of this is just excercising the code paths to make sure there are no
// Some of this is just exercising the code paths to make sure there are no
// panics.
func TestPingFail(t *testing.T) {
var withHeader bool

View file

@ -2,14 +2,13 @@ package client // import "github.com/docker/docker/client"
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"
"context"
"github.com/docker/docker/api/types"
)

View file

@ -61,7 +61,7 @@ func TestSetHostHeader(t *testing.T) {
}
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewReader(([]byte("")))),
Body: ioutil.NopCloser(bytes.NewReader([]byte(""))),
}, nil
}),

View file

@ -9,7 +9,7 @@ import (
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
@ -136,7 +136,7 @@ func imageWithDigestString(image string, dgst digest.Digest) string {
// imageWithTagString takes an image string, and returns a tagged image
// string, adding a 'latest' tag if one was not provided. It returns an
// emptry string if a canonical reference was provided
// empty string if a canonical reference was provided
func imageWithTagString(image string) string {
namedRef, err := reference.ParseNormalizedNamed(image)
if err == nil {

View file

@ -8,6 +8,7 @@ import (
"github.com/docker/docker/api/types"
timetypes "github.com/docker/docker/api/types/time"
"github.com/pkg/errors"
)
// ServiceLogs returns the logs generated by a service in an io.ReadCloser.
@ -25,7 +26,7 @@ func (cli *Client) ServiceLogs(ctx context.Context, serviceID string, options ty
if options.Since != "" {
ts, err := timetypes.GetTimestamp(options.Since, time.Now())
if err != nil {
return nil, err
return nil, errors.Wrap(err, `invalid value for "since"`)
}
query.Set("since", ts)
}

View file

@ -2,6 +2,7 @@ package client // import "github.com/docker/docker/client"
import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
@ -12,9 +13,9 @@ import (
"testing"
"time"
"context"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
)
func TestServiceLogsError(t *testing.T) {
@ -22,15 +23,11 @@ func TestServiceLogsError(t *testing.T) {
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.ServiceLogs(context.Background(), "service_id", types.ContainerLogsOptions{})
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
assert.Check(t, is.Error(err, "Error response from daemon: Server error"))
_, err = client.ServiceLogs(context.Background(), "service_id", types.ContainerLogsOptions{
Since: "2006-01-02TZ",
})
if err == nil || !strings.Contains(err.Error(), `parsing time "2006-01-02TZ"`) {
t.Fatalf("expected a 'parsing time' error, got %v", err)
}
assert.Check(t, is.ErrorContains(err, `parsing time "2006-01-02TZ"`))
}
func TestServiceLogs(t *testing.T) {
@ -38,6 +35,7 @@ func TestServiceLogs(t *testing.T) {
cases := []struct {
options types.ContainerLogsOptions
expectedQueryParams map[string]string
expectedError string
}{
{
expectedQueryParams: map[string]string{
@ -71,21 +69,27 @@ func TestServiceLogs(t *testing.T) {
},
{
options: types.ContainerLogsOptions{
// An complete invalid date, timestamp or go duration will be
// passed as is
Since: "invalid but valid",
// timestamp will be passed as is
Since: "1136073600.000000001",
},
expectedQueryParams: map[string]string{
"tail": "",
"since": "invalid but valid",
"since": "1136073600.000000001",
},
},
{
options: types.ContainerLogsOptions{
// An complete invalid date will not be passed
Since: "invalid value",
},
expectedError: `invalid value for "since": failed to parse value as time or duration: "invalid value"`,
},
}
for _, logCase := range cases {
client := &Client{
client: newMockClient(func(r *http.Request) (*http.Response, error) {
if !strings.HasPrefix(r.URL.Path, expectedURL) {
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, r.URL)
return nil, fmt.Errorf("expected URL '%s', got '%s'", expectedURL, r.URL)
}
// Check query parameters
query := r.URL.Query()
@ -102,17 +106,15 @@ func TestServiceLogs(t *testing.T) {
}),
}
body, err := client.ServiceLogs(context.Background(), "service_id", logCase.options)
if err != nil {
t.Fatal(err)
if logCase.expectedError != "" {
assert.Check(t, is.Error(err, logCase.expectedError))
continue
}
assert.NilError(t, err)
defer body.Close()
content, err := ioutil.ReadAll(body)
if err != nil {
t.Fatal(err)
}
if string(content) != "response" {
t.Fatalf("expected response to contain 'response', got %s", string(content))
}
assert.NilError(t, err)
assert.Check(t, is.Contains(string(content), "response"))
}
}

View file

@ -11,7 +11,6 @@ import (
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/internal/testutil"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
)
@ -22,7 +21,7 @@ func TestSwarmGetUnlockKeyError(t *testing.T) {
}
_, err := client.SwarmGetUnlockKey(context.Background())
testutil.ErrorContains(t, err, "Error response from daemon: Server error")
assert.Check(t, is.ErrorContains(err, "Error response from daemon: Server error"))
}
func TestSwarmGetUnlockKey(t *testing.T) {

View file

@ -17,7 +17,7 @@ func TestSwarmUnlockError(t *testing.T) {
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
err := client.SwarmUnlock(context.Background(), swarm.UnlockRequest{"SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"})
err := client.SwarmUnlock(context.Background(), swarm.UnlockRequest{UnlockKey: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"})
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
@ -41,7 +41,7 @@ func TestSwarmUnlock(t *testing.T) {
}),
}
err := client.SwarmUnlock(context.Background(), swarm.UnlockRequest{"SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"})
err := client.SwarmUnlock(context.Background(), swarm.UnlockRequest{UnlockKey: "SWMKEY-1-y6guTZNTwpQeTL5RhUfOsdBdXoQjiB2GADHSRJvbXeU"})
if err != nil {
t.Fatal(err)
}

View file

@ -9,7 +9,7 @@ import (
)
// VolumeCreate creates a volume in the docker host.
func (cli *Client) VolumeCreate(ctx context.Context, options volumetypes.VolumesCreateBody) (types.Volume, error) {
func (cli *Client) VolumeCreate(ctx context.Context, options volumetypes.VolumeCreateBody) (types.Volume, error) {
var volume types.Volume
resp, err := cli.post(ctx, "/volumes/create", nil, options, nil)
if err != nil {

View file

@ -19,7 +19,7 @@ func TestVolumeCreateError(t *testing.T) {
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}
_, err := client.VolumeCreate(context.Background(), volumetypes.VolumesCreateBody{})
_, err := client.VolumeCreate(context.Background(), volumetypes.VolumeCreateBody{})
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
@ -53,7 +53,7 @@ func TestVolumeCreate(t *testing.T) {
}),
}
volume, err := client.VolumeCreate(context.Background(), volumetypes.VolumesCreateBody{
volume, err := client.VolumeCreate(context.Background(), volumetypes.VolumeCreateBody{
Name: "myvolume",
Driver: "mydriver",
DriverOpts: map[string]string{

View file

@ -11,7 +11,6 @@ import (
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/internal/testutil"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
@ -23,7 +22,7 @@ func TestVolumeInspectError(t *testing.T) {
}
_, err := client.VolumeInspect(context.Background(), "nothing")
testutil.ErrorContains(t, err, "Error response from daemon: Server error")
assert.Check(t, is.ErrorContains(err, "Error response from daemon: Server error"))
}
func TestVolumeInspectNotFound(t *testing.T) {

View file

@ -10,8 +10,8 @@ import (
)
// VolumeList returns the volumes configured in the docker host.
func (cli *Client) VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumesListOKBody, error) {
var volumes volumetypes.VolumesListOKBody
func (cli *Client) VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumeListOKBody, error) {
var volumes volumetypes.VolumeListOKBody
query := url.Values{}
if filter.Len() > 0 {

View file

@ -69,7 +69,7 @@ func TestVolumeList(t *testing.T) {
if actualFilters != listCase.expectedFilters {
return nil, fmt.Errorf("filters not set in URL query properly. Expected '%s', got %s", listCase.expectedFilters, actualFilters)
}
content, err := json.Marshal(volumetypes.VolumesListOKBody{
content, err := json.Marshal(volumetypes.VolumeListOKBody{
Volumes: []*types.Volume{
{
Name: "volume",

View file

@ -47,7 +47,7 @@ func IsConflict(err error) bool {
return ok
}
// IsUnauthorized returns if the the passed in error is an ErrUnauthorized
// IsUnauthorized returns if the passed in error is an ErrUnauthorized
func IsUnauthorized(err error) bool {
_, ok := getImplementer(err).(ErrUnauthorized)
return ok

View file

@ -30,8 +30,8 @@ func (e ranges) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
func (e ranges) Less(i, j int) bool { return e[i].Start < e[j].Start }
const (
subuidFileName string = "/etc/subuid"
subgidFileName string = "/etc/subgid"
subuidFileName = "/etc/subuid"
subgidFileName = "/etc/subgid"
)
// MkdirAllAndChown creates a directory (include any along the path) and then modifies

View file

@ -8,9 +8,9 @@ import (
"strings"
"time"
gotty "github.com/Nvveen/Gotty"
"github.com/Nvveen/Gotty"
"github.com/docker/docker/pkg/term"
units "github.com/docker/go-units"
"github.com/docker/go-units"
)
// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to
@ -245,7 +245,7 @@ func (jm *JSONMessage) Display(out io.Writer, termInfo termInfo) error {
// DisplayJSONMessagesStream displays a json message stream from `in` to `out`, `isTerminal`
// describes if `out` is a terminal. If this is the case, it will print `\n` at the end of
// each line and move the cursor while displaying.
func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(*json.RawMessage)) error {
func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(JSONMessage)) error {
var (
dec = json.NewDecoder(in)
ids = make(map[string]int)
@ -277,7 +277,7 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr,
if jm.Aux != nil {
if auxCallback != nil {
auxCallback(jm.Aux)
auxCallback(jm)
}
continue
}
@ -330,6 +330,6 @@ type stream interface {
}
// DisplayJSONMessagesToStream prints json messages to the output stream
func DisplayJSONMessagesToStream(in io.Reader, stream stream, auxCallback func(*json.RawMessage)) error {
func DisplayJSONMessagesToStream(in io.Reader, stream stream, auxCallback func(JSONMessage)) error {
return DisplayJSONMessagesStream(in, stream, stream.FD(), stream.IsTerminal(), auxCallback)
}

View file

@ -8,8 +8,6 @@ import (
"os"
"strings"
"testing"
selinux "github.com/opencontainers/selinux/go-selinux"
)
func TestMount(t *testing.T) {
@ -103,11 +101,7 @@ func TestMount(t *testing.T) {
t.Fatal(err)
}
defer ensureUnmount(t, target)
expectedVFS := tc.expectedVFS
if selinux.GetEnabled() && expectedVFS != "" {
expectedVFS = expectedVFS + ",seclabel"
}
validateMount(t, target, tc.expectedOpts, tc.expectedOptional, expectedVFS)
validateMount(t, target, tc.expectedOpts, tc.expectedOptional, tc.expectedVFS)
})
}
}
@ -177,13 +171,13 @@ func validateMount(t *testing.T, mnt string, opts, optional, vfs string) {
for _, opt := range strings.Split(mi.Opts, ",") {
opt = clean(opt)
if !has(wantedOpts, opt) && !has(pOpts, opt) {
t.Errorf("unexpected mount option %q expected %q", opt, opts)
t.Errorf("unexpected mount option %q, expected %q", opt, opts)
}
delete(wantedOpts, opt)
}
}
for opt := range wantedOpts {
t.Errorf("missing mount option %q found %q", opt, mi.Opts)
t.Errorf("missing mount option %q, found %q", opt, mi.Opts)
}
// Validate Optional
@ -191,13 +185,13 @@ func validateMount(t *testing.T, mnt string, opts, optional, vfs string) {
for _, field := range strings.Split(mi.Optional, ",") {
field = clean(field)
if !has(wantedOptional, field) && !has(pOptional, field) {
t.Errorf("unexpected optional failed %q expected %q", field, optional)
t.Errorf("unexpected optional field %q, expected %q", field, optional)
}
delete(wantedOptional, field)
}
}
for field := range wantedOptional {
t.Errorf("missing optional field %q found %q", field, mi.Optional)
t.Errorf("missing optional field %q, found %q", field, mi.Optional)
}
// Validate VFS if set
@ -205,14 +199,14 @@ func validateMount(t *testing.T, mnt string, opts, optional, vfs string) {
if mi.VfsOpts != "" {
for _, opt := range strings.Split(mi.VfsOpts, ",") {
opt = clean(opt)
if !has(wantedVFS, opt) {
t.Errorf("unexpected mount option %q expected %q", opt, vfs)
if !has(wantedVFS, opt) && opt != "seclabel" { // can be added by selinux
t.Errorf("unexpected vfs option %q, expected %q", opt, vfs)
}
delete(wantedVFS, opt)
}
}
for opt := range wantedVFS {
t.Errorf("missing mount option %q found %q", opt, mi.VfsOpts)
t.Errorf("missing vfs option %q, found %q", opt, mi.VfsOpts)
}
}

View file

@ -9,7 +9,7 @@ import (
"os"
"sync"
ansiterm "github.com/Azure/go-ansiterm"
"github.com/Azure/go-ansiterm"
"github.com/sirupsen/logrus"
)

View file

@ -100,7 +100,7 @@ func TestLoadAllowNondistributableArtifacts(t *testing.T) {
t.Fatalf("expect no error, got '%s'", err)
}
cidrStrs := []string{}
var cidrStrs []string
for _, c := range config.AllowNondistributableArtifactsCIDRs {
cidrStrs = append(cidrStrs, c.String())
}

View file

@ -69,7 +69,7 @@ func validateEndpoint(endpoint *V1Endpoint) error {
func newV1Endpoint(address url.URL, tlsConfig *tls.Config, userAgent string, metaHeaders http.Header) *V1Endpoint {
endpoint := &V1Endpoint{
IsSecure: (tlsConfig == nil || !tlsConfig.InsecureSkipVerify),
IsSecure: tlsConfig == nil || !tlsConfig.InsecureSkipVerify,
URL: new(url.URL),
}

View file

@ -430,7 +430,7 @@ func handlerImages(w http.ResponseWriter, r *http.Request) {
writeResponse(w, "", 204)
return
}
images := []map[string]string{}
var images []map[string]string
for imageID, layer := range testLayers {
image := make(map[string]string)
image["id"] = imageID

View file

@ -543,7 +543,7 @@ func TestNewIndexInfo(t *testing.T) {
}
config := emptyServiceConfig
noMirrors := []string{}
var noMirrors []string
expectedIndexInfos := map[string]*registrytypes.IndexInfo{
IndexName: {
Name: IndexName,

View file

@ -3,7 +3,6 @@ package registry // import "github.com/docker/docker/registry"
import (
"bytes"
"crypto/sha256"
"sync"
// this is required for some certificates
_ "crypto/sha512"
"encoding/hex"
@ -16,6 +15,7 @@ import (
"net/url"
"strconv"
"strings"
"sync"
"github.com/docker/distribution/reference"
"github.com/docker/distribution/registry/api/errcode"

View file

@ -1,7 +1,7 @@
# the following lines are in sorted order, FYI
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
github.com/Microsoft/hcsshim v0.6.11
github.com/Microsoft/go-winio v0.4.6
github.com/Microsoft/go-winio v0.4.7
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a
@ -26,13 +26,16 @@ github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
github.com/imdario/mergo 0.2.1
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
# buildkit
github.com/moby/buildkit 43e758232a0ac7d50c6a11413186e16684fc1e4f
github.com/tonistiigi/fsutil dc68c74458923f357474a9178bd198aa3ed11a5f
github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
#get libnetwork packages
# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy accordingly
github.com/docker/libnetwork c15b372ef22125880d378167dde44f4b134e1a77
github.com/docker/libnetwork eb6b2a57955e5c149d47c3973573216e8f8baa09
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
@ -67,19 +70,19 @@ github.com/opencontainers/go-digest v1.0.0-rc1
github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa
github.com/pborman/uuid v1.0
google.golang.org/grpc v1.3.0
google.golang.org/grpc v1.12.0
# When updating, also update RUNC_COMMIT in hack/dockerfile/install/runc accordingly
github.com/opencontainers/runc 4fc53a81fb7c994640722ac585fa9ca548971871
github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340
github.com/opencontainers/runtime-spec v1.0.1
github.com/opencontainers/image-spec v1.0.1
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
# libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json)
github.com/coreos/go-systemd v15
github.com/coreos/go-systemd v17
github.com/godbus/dbus v4.0.0
github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852
github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
github.com/golang/protobuf v1.1.0
# gelf logging driver deps
github.com/Graylog2/go-gelf 4143646226541087117ff2f83334ea48b3201841
@ -101,26 +104,27 @@ github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74
github.com/bsphere/le_go 7a984a84b5492ae539b79b62fb4a10afc63c7bcf
# gcplogs deps
golang.org/x/oauth2 96382aa079b72d8c014eb0c50f6c223d1e6a2de0
google.golang.org/api 3cc2e591b550923a2c5f0ab5a803feda924d5823
cloud.google.com/go 9d965e63e8cceb1b5d7977a202f0fcb8866d6525
github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
golang.org/x/oauth2 ec22f46f877b4505e0117eeaab541714644fdd28
google.golang.org/api de943baf05a022a8f921b544b7827bacaba1aed5
go.opencensus.io v0.11.0
cloud.google.com/go v0.23.0
github.com/googleapis/gax-go v2.0.0
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
# containerd
github.com/containerd/containerd 4ac4fd0b6a268fe6f38b2b2e32e40daa7e424fac
github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6
github.com/containerd/continuity d8fb8589b0e8e85b8c8bbaa8840226d0dfeb7371
github.com/containerd/containerd c7083eed5d8633d54c25fe81aa609010a4f2e495
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130
github.com/containerd/console 2748ece16665b45a47f884001d5831ec79703880
github.com/containerd/go-runc 4f6e87ae043f859a38255247b49c9abc262d002f
github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925
github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd
github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
github.com/dmcgowan/go-tar go1.10
github.com/stevvooe/ttrpc d4528379866b0ce7e9d71f3eb96f0582fc374577
github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
# cluster
github.com/docker/swarmkit bd69f6e8e301645afd344913fa1ede53a0a111fb
github.com/gogo/protobuf v0.4
github.com/docker/swarmkit edd5641391926a50bc5f7040e20b7efc05003c26
github.com/gogo/protobuf v1.0.0
github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
github.com/fernet/fernet-go 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2
github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e
@ -141,8 +145,8 @@ github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
# cli
github.com/spf13/cobra v1.5.1 https://github.com/dnephin/cobra.git
github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.1
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty

View file

@ -7,13 +7,13 @@ matrix:
- go: 1.4
- go: 1.5
- go: 1.6
- go: 1.7
- go: tip
allow_failures:
- go: tip
install:
- go get golang.org/x/tools/cmd/vet
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d .)
- go tool vet .
- go vet $(go list ./... | grep -v /vendor/)
- go test -v -race ./...

View file

@ -4,4 +4,7 @@ context
gorilla/context is a general purpose registry for global request variables.
> Note: gorilla/context, having been born well before `context.Context` existed, does not play well
> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. You should either use *just* gorilla/context, or moving forward, the new `http.Request.Context()`.
Read the full documentation here: http://www.gorillatoolkit.org/pkg/context

View file

@ -69,7 +69,7 @@ func TestContext(t *testing.T) {
// GetAllOk() for empty request
values, ok = GetAllOk(emptyR)
assertEqual(value, nil)
assertEqual(len(values), 0)
assertEqual(ok, false)
// Delete()

View file

@ -5,6 +5,12 @@
/*
Package context stores values shared during a request lifetime.
Note: gorilla/context, having been born well before `context.Context` existed,
does not play well > with the shallow copying of the request that
[`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext)
(added to net/http Go 1.7 onwards) performs. You should either use *just*
gorilla/context, or moving forward, the new `http.Request.Context()`.
For example, a router can set variables extracted from the URL and later
application handlers can access those values, or it can be used to store
sessions values to be saved at the end of a request. There are several

View file

@ -3,11 +3,12 @@ sudo: false
matrix:
include:
- go: 1.5
- go: 1.6
- go: 1.7
- go: 1.8
- go: 1.9
- go: 1.5.x
- go: 1.6.x
- go: 1.7.x
- go: 1.8.x
- go: 1.9.x
- go: 1.10.x
- go: tip
allow_failures:
- go: tip

View file

@ -1,5 +1,5 @@
gorilla/mux
===
# gorilla/mux
[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge)
@ -29,6 +29,7 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
* [Walking Routes](#walking-routes)
* [Graceful Shutdown](#graceful-shutdown)
* [Middleware](#middleware)
* [Testing Handlers](#testing-handlers)
* [Full Example](#full-example)
---
@ -178,70 +179,13 @@ s.HandleFunc("/{key}/", ProductHandler)
// "/products/{key}/details"
s.HandleFunc("/{key}/details", ProductDetailsHandler)
```
### Listing Routes
Routes on a mux can be listed using the Router.Walk method—useful for generating documentation:
```go
package main
import (
"fmt"
"net/http"
"strings"
"github.com/gorilla/mux"
)
func handler(w http.ResponseWriter, r *http.Request) {
return
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.HandleFunc("/products", handler).Methods("POST")
r.HandleFunc("/articles", handler).Methods("GET")
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
t, err := route.GetPathTemplate()
if err != nil {
return err
}
qt, err := route.GetQueriesTemplates()
if err != nil {
return err
}
// p will contain regular expression is compatible with regular expression in Perl, Python, and other languages.
// for instance the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'
p, err := route.GetPathRegexp()
if err != nil {
return err
}
// qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
// just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
// {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
qr, err := route.GetQueriesRegexp()
if err != nil {
return err
}
m, err := route.GetMethods()
if err != nil {
return err
}
fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
return nil
})
http.Handle("/", r)
}
```
### Static Files
Note that the path provided to `PathPrefix()` represents a "wildcard": calling
`PathPrefix("/static/").Handler(...)` means that the handler will be passed any
request that matches "/static/*". This makes it easy to serve static files with mux:
request that matches "/static/\*". This makes it easy to serve static files with mux:
```go
func main() {
@ -348,41 +292,58 @@ The `Walk` function on `mux.Router` can be used to visit all of the routes that
the following prints all of the registered routes:
```go
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.HandleFunc("/products", handler).Methods("POST")
r.HandleFunc("/articles", handler).Methods("GET")
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
t, err := route.GetPathTemplate()
if err != nil {
return err
}
qt, err := route.GetQueriesTemplates()
if err != nil {
return err
}
// p will contain a regular expression that is compatible with regular expressions in Perl, Python, and other languages.
// For example, the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'.
p, err := route.GetPathRegexp()
if err != nil {
return err
}
// qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
// just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
// {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
qr, err := route.GetQueriesRegexp()
if err != nil {
return err
}
m, err := route.GetMethods()
if err != nil {
return err
}
fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
return nil
})
package main
import (
"fmt"
"net/http"
"strings"
"github.com/gorilla/mux"
)
func handler(w http.ResponseWriter, r *http.Request) {
return
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.HandleFunc("/products", handler).Methods("POST")
r.HandleFunc("/articles", handler).Methods("GET")
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
pathTemplate, err := route.GetPathTemplate()
if err == nil {
fmt.Println("ROUTE:", pathTemplate)
}
pathRegexp, err := route.GetPathRegexp()
if err == nil {
fmt.Println("Path regexp:", pathRegexp)
}
queriesTemplates, err := route.GetQueriesTemplates()
if err == nil {
fmt.Println("Queries templates:", strings.Join(queriesTemplates, ","))
}
queriesRegexps, err := route.GetQueriesRegexp()
if err == nil {
fmt.Println("Queries regexps:", strings.Join(queriesRegexps, ","))
}
methods, err := route.GetMethods()
if err == nil {
fmt.Println("Methods:", strings.Join(methods, ","))
}
fmt.Println()
return nil
})
if err != nil {
fmt.Println(err)
}
http.Handle("/", r)
}
```
### Graceful Shutdown
@ -399,6 +360,7 @@ import (
"net/http"
"os"
"os/signal"
"time"
"github.com/gorilla/mux"
)
@ -410,7 +372,7 @@ func main() {
r := mux.NewRouter()
// Add your routes as needed
srv := &http.Server{
Addr: "0.0.0.0:8080",
// Good practice to set timeouts to avoid Slowloris attacks.
@ -426,7 +388,7 @@ func main() {
log.Println(err)
}
}()
c := make(chan os.Signal, 1)
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
@ -436,7 +398,8 @@ func main() {
<-c
// Create a deadline to wait for.
ctx, cancel := context.WithTimeout(ctx, wait)
ctx, cancel := context.WithTimeout(context.Background(), wait)
defer cancel()
// Doesn't block if no connections, but will otherwise wait
// until the timeout deadline.
srv.Shutdown(ctx)
@ -464,7 +427,7 @@ Typically, the returned handler is a closure which does something with the http.
A very basic middleware which logs the URI of the request being handled could be written as:
```go
func simpleMw(next http.Handler) http.Handler {
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do stuff here
log.Println(r.RequestURI)
@ -474,12 +437,12 @@ func simpleMw(next http.Handler) http.Handler {
}
```
Middlewares can be added to a router using `Router.AddMiddlewareFunc()`:
Middlewares can be added to a router using `Router.Use()`:
```go
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.AddMiddleware(simpleMw)
r.Use(loggingMiddleware)
```
A more complex authentication middleware, which maps session token to users, could be written as:
@ -502,7 +465,7 @@ func (amw *authenticationMiddleware) Populate() {
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Session-Token")
if user, found := amw.tokenUsers[token]; found {
// We found the token in our map
log.Printf("Authenticated user %s\n", user)
@ -510,7 +473,7 @@ func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler
next.ServeHTTP(w, r)
} else {
// Write an error and stop the handler chain
http.Error(w, "Forbidden", 403)
http.Error(w, "Forbidden", http.StatusForbidden)
}
})
}
@ -523,10 +486,136 @@ r.HandleFunc("/", handler)
amw := authenticationMiddleware{}
amw.Populate()
r.AddMiddlewareFunc(amw.Middleware)
r.Use(amw.Middleware)
```
Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares *should* write to `ResponseWriter` if they *are* going to terminate the request, and they *should not* write to `ResponseWriter` if they *are not* going to terminate it.
Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it.
### Testing Handlers
Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_.
First, our simple HTTP handler:
```go
// endpoints.go
package main
func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
// A very simple health check.
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
// In the future we could report back on the status of our DB, or our cache
// (e.g. Redis) by performing a simple PING, and include them in the response.
io.WriteString(w, `{"alive": true}`)
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/health", HealthCheckHandler)
log.Fatal(http.ListenAndServe("localhost:8080", r))
}
```
Our test code:
```go
// endpoints_test.go
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestHealthCheckHandler(t *testing.T) {
// Create a request to pass to our handler. We don't have any query parameters for now, so we'll
// pass 'nil' as the third parameter.
req, err := http.NewRequest("GET", "/health", nil)
if err != nil {
t.Fatal(err)
}
// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
rr := httptest.NewRecorder()
handler := http.HandlerFunc(HealthCheckHandler)
// Our handlers satisfy http.Handler, so we can call their ServeHTTP method
// directly and pass in our Request and ResponseRecorder.
handler.ServeHTTP(rr, req)
// Check the status code is what we expect.
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
// Check the response body is what we expect.
expected := `{"alive": true}`
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
}
```
In the case that our routes have [variables](#examples), we can pass those in the request. We could write
[table-driven tests](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) to test multiple
possible route variables as needed.
```go
// endpoints.go
func main() {
r := mux.NewRouter()
// A route with a route variable:
r.HandleFunc("/metrics/{type}", MetricsHandler)
log.Fatal(http.ListenAndServe("localhost:8080", r))
}
```
Our test file, with a table-driven test of `routeVariables`:
```go
// endpoints_test.go
func TestMetricsHandler(t *testing.T) {
tt := []struct{
routeVariable string
shouldPass bool
}{
{"goroutines", true},
{"heap", true},
{"counters", true},
{"queries", true},
{"adhadaeqm3k", false},
}
for _, tc := range tt {
path := fmt.Sprintf("/metrics/%s", tc.routeVariable)
req, err := http.NewRequest("GET", path, nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
// Need to create a router that we can pass the request through so that the vars will be added to the context
router := mux.NewRouter()
router.HandleFunc("/metrics/{type}", MetricsHandler)
router.ServeHTTP(rr, req)
// In this case, our MetricsHandler returns a non-200 response
// for a route variable it doesn't know about.
if rr.Code == http.StatusOK && !tc.shouldPass {
t.Errorf("handler should have failed on routeVariable %s: got %v want %v",
tc.routeVariable, rr.Code, http.StatusOK)
}
}
}
```
## Full Example

View file

@ -239,8 +239,7 @@ as well:
"category", "technology",
"id", "42")
Since **vX.Y.Z**, mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed if a
match is found (including subrouters). Middlewares are defined using the de facto standard type:
Mux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters. Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or ResponseWriter hijacking.
type MiddlewareFunc func(http.Handler) http.Handler
@ -261,7 +260,7 @@ Middlewares can be added to a router using `Router.Use()`:
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.AddMiddleware(simpleMw)
r.Use(simpleMw)
A more complex authentication middleware, which maps session token to users, could be written as:
@ -288,7 +287,7 @@ A more complex authentication middleware, which maps session token to users, cou
log.Printf("Authenticated user %s\n", user)
next.ServeHTTP(w, r)
} else {
http.Error(w, "Forbidden", 403)
http.Error(w, "Forbidden", http.StatusForbidden)
}
})
}

View file

@ -0,0 +1,46 @@
package mux_test
import (
"log"
"net/http"
"github.com/gorilla/mux"
)
// Define our struct
type authenticationMiddleware struct {
tokenUsers map[string]string
}
// Initialize it somewhere
func (amw *authenticationMiddleware) Populate() {
amw.tokenUsers["00000000"] = "user0"
amw.tokenUsers["aaaaaaaa"] = "userA"
amw.tokenUsers["05f717e5"] = "randomUser"
amw.tokenUsers["deadbeef"] = "user0"
}
// Middleware function, which will be called for each request
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Session-Token")
if user, found := amw.tokenUsers[token]; found {
// We found the token in our map
log.Printf("Authenticated user %s\n", user)
next.ServeHTTP(w, r)
} else {
http.Error(w, "Forbidden", http.StatusForbidden)
}
})
}
func Example_authenticationMiddleware() {
r := mux.NewRouter()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Do something here
})
amw := authenticationMiddleware{}
amw.Populate()
r.Use(amw.Middleware)
}

View file

@ -1,6 +1,9 @@
package mux
import "net/http"
import (
"net/http"
"strings"
)
// MiddlewareFunc is a function which receives an http.Handler and returns another http.Handler.
// Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed
@ -12,17 +15,58 @@ type middleware interface {
Middleware(handler http.Handler) http.Handler
}
// MiddlewareFunc also implements the middleware interface.
// Middleware allows MiddlewareFunc to implement the middleware interface.
func (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler {
return mw(handler)
}
// Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
func (r *Router) Use(mwf MiddlewareFunc) {
r.middlewares = append(r.middlewares, mwf)
func (r *Router) Use(mwf ...MiddlewareFunc) {
for _, fn := range mwf {
r.middlewares = append(r.middlewares, fn)
}
}
// useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
func (r *Router) useInterface(mw middleware) {
r.middlewares = append(r.middlewares, mw)
}
// CORSMethodMiddleware sets the Access-Control-Allow-Methods response header
// on a request, by matching routes based only on paths. It also handles
// OPTIONS requests, by settings Access-Control-Allow-Methods, and then
// returning without calling the next http handler.
func CORSMethodMiddleware(r *Router) MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var allMethods []string
err := r.Walk(func(route *Route, _ *Router, _ []*Route) error {
for _, m := range route.matchers {
if _, ok := m.(*routeRegexp); ok {
if m.Match(req, &RouteMatch{}) {
methods, err := route.GetMethods()
if err != nil {
return err
}
allMethods = append(allMethods, methods...)
}
break
}
}
return nil
})
if err == nil {
w.Header().Set("Access-Control-Allow-Methods", strings.Join(append(allMethods, "OPTIONS"), ","))
if req.Method == "OPTIONS" {
return
}
}
next.ServeHTTP(w, req)
})
}
}

View file

@ -3,6 +3,7 @@ package mux
import (
"bytes"
"net/http"
"net/http/httptest"
"testing"
)
@ -334,3 +335,43 @@ func TestMiddlewareMethodMismatchSubrouter(t *testing.T) {
t.Fatal("Middleware was called for a method mismatch")
}
}
func TestCORSMethodMiddleware(t *testing.T) {
router := NewRouter()
cases := []struct {
path string
response string
method string
testURL string
expectedAllowedMethods string
}{
{"/g/{o}", "a", "POST", "/g/asdf", "POST,PUT,GET,OPTIONS"},
{"/g/{o}", "b", "PUT", "/g/bla", "POST,PUT,GET,OPTIONS"},
{"/g/{o}", "c", "GET", "/g/orilla", "POST,PUT,GET,OPTIONS"},
{"/g", "d", "POST", "/g", "POST,OPTIONS"},
}
for _, tt := range cases {
router.HandleFunc(tt.path, stringHandler(tt.response)).Methods(tt.method)
}
router.Use(CORSMethodMiddleware(router))
for _, tt := range cases {
rr := httptest.NewRecorder()
req := newRequest(tt.method, tt.testURL)
router.ServeHTTP(rr, req)
if rr.Body.String() != tt.response {
t.Errorf("Expected body '%s', found '%s'", tt.response, rr.Body.String())
}
allowedMethods := rr.HeaderMap.Get("Access-Control-Allow-Methods")
if allowedMethods != tt.expectedAllowedMethods {
t.Errorf("Expected Access-Control-Allow-Methods '%s', found '%s'", tt.expectedAllowedMethods, allowedMethods)
}
}
}

View file

@ -13,8 +13,11 @@ import (
)
var (
// ErrMethodMismatch is returned when the method in the request does not match
// the method defined against the route.
ErrMethodMismatch = errors.New("method is not allowed")
ErrNotFound = errors.New("no matching route was found")
// ErrNotFound is returned when no route match is found.
ErrNotFound = errors.New("no matching route was found")
)
// NewRouter returns a new router instance.
@ -95,9 +98,9 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
if r.MethodNotAllowedHandler != nil {
match.Handler = r.MethodNotAllowedHandler
return true
} else {
return false
}
return false
}
// Closest match for a router (includes sub-routers)

View file

@ -2248,6 +2248,15 @@ func TestMethodsSubrouterPathVariable(t *testing.T) {
}
}
func ExampleSetURLVars() {
req, _ := http.NewRequest("GET", "/foo", nil)
req = SetURLVars(req, map[string]string{"foo": "bar"})
fmt.Println(Vars(req)["foo"])
// Output: bar
}
// testMethodsSubrouter runs an individual methodsSubrouterTest.
func testMethodsSubrouter(t *testing.T, test methodsSubrouterTest) {
// Execute request
@ -2306,6 +2315,14 @@ func stringMapEqual(m1, m2 map[string]string) bool {
return true
}
// stringHandler returns a handler func that writes a message 's' to the
// http.ResponseWriter.
func stringHandler(s string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(s))
}
}
// newRequest is a helper function to create a new request with a method and url.
// The request returned is a 'server' request as opposed to a 'client' one through
// simulated write onto the wire and read off of the wire.

View file

@ -43,6 +43,8 @@ type Route struct {
buildVarsFunc BuildVarsFunc
}
// SkipClean reports whether path cleaning is enabled for this route via
// Router.SkipClean.
func (r *Route) SkipClean() bool {
return r.skipClean
}
@ -622,7 +624,7 @@ func (r *Route) GetPathRegexp() (string, error) {
// route queries.
// This is useful for building simple REST API documentation and for instrumentation
// against third-party services.
// An empty list will be returned if the route does not have queries.
// An error will be returned if the route does not have queries.
func (r *Route) GetQueriesRegexp() ([]string, error) {
if r.err != nil {
return nil, r.err
@ -641,7 +643,7 @@ func (r *Route) GetQueriesRegexp() ([]string, error) {
// query matching.
// This is useful for building simple REST API documentation and for instrumentation
// against third-party services.
// An empty list will be returned if the route does not define queries.
// An error will be returned if the route does not define queries.
func (r *Route) GetQueriesTemplates() ([]string, error) {
if r.err != nil {
return nil, r.err
@ -659,7 +661,7 @@ func (r *Route) GetQueriesTemplates() ([]string, error) {
// GetMethods returns the methods the route matches against
// This is useful for building simple REST API documentation and for instrumentation
// against third-party services.
// An empty list will be returned if route does not have methods.
// An error will be returned if route does not have methods.
func (r *Route) GetMethods() ([]string, error) {
if r.err != nil {
return nil, r.err
@ -669,7 +671,7 @@ func (r *Route) GetMethods() ([]string, error) {
return []string(methods), nil
}
}
return nil, nil
return nil, errors.New("mux: route doesn't have methods")
}
// GetHostTemplate returns the template used to build the

View file

@ -7,7 +7,8 @@ package mux
import "net/http"
// SetURLVars sets the URL variables for the given request, to be accessed via
// mux.Vars for testing route behaviour.
// mux.Vars for testing route behaviour. Arguments are not modified, a shallow
// copy is returned.
//
// This API should only be used for testing purposes; it provides a way to
// inject variables into the request context. Alternatively, URL variables

View file

@ -1,2 +1,8 @@
language: go
go:
- 1.5
- 1.6
- tip
script: make -f Makefile.TRAVIS

View file

@ -0,0 +1,15 @@
all: build cover test vet
build:
go build -v ./...
cover: test
$(MAKE) -C pbutil cover
test: build
go test -v ./...
vet: build
go vet -v ./...
.PHONY: build cover test vet

View file

@ -0,0 +1 @@
cover.dat

View file

@ -0,0 +1,7 @@
all:
cover:
go test -cover -v -coverprofile=cover.dat ./...
go tool cover -func cover.dat
.PHONY: cover

View file

@ -18,14 +18,15 @@ import (
"bytes"
"testing"
. "github.com/golang/protobuf/proto"
. "github.com/golang/protobuf/proto/testdata"
"github.com/golang/protobuf/proto"
. "github.com/matttproud/golang_protobuf_extensions/testdata"
)
func TestWriteDelimited(t *testing.T) {
t.Parallel()
for _, test := range []struct {
msg Message
msg proto.Message
buf []byte
n int
err error
@ -42,7 +43,7 @@ func TestWriteDelimited(t *testing.T) {
},
{
msg: &Strings{
StringField: String(`This is my gigantic, unhappy string. It exceeds
StringField: proto.String(`This is my gigantic, unhappy string. It exceeds
the encoding size of a single byte varint. We are using it to fuzz test the
correctness of the header decoding mechanisms, which may prove problematic.
I expect it may. Let's hope you enjoy testing as much as we do.`),
@ -82,7 +83,7 @@ func TestReadDelimited(t *testing.T) {
t.Parallel()
for _, test := range []struct {
buf []byte
msg Message
msg proto.Message
n int
err error
}{
@ -116,7 +117,7 @@ func TestReadDelimited(t *testing.T) {
106, 111, 121, 32, 116, 101, 115, 116, 105, 110, 103, 32, 97, 115, 32,
109, 117, 99, 104, 32, 97, 115, 32, 119, 101, 32, 100, 111, 46},
msg: &Strings{
StringField: String(`This is my gigantic, unhappy string. It exceeds
StringField: proto.String(`This is my gigantic, unhappy string. It exceeds
the encoding size of a single byte varint. We are using it to fuzz test the
correctness of the header decoding mechanisms, which may prove problematic.
I expect it may. Let's hope you enjoy testing as much as we do.`),
@ -124,12 +125,12 @@ I expect it may. Let's hope you enjoy testing as much as we do.`),
n: 271,
},
} {
msg := Clone(test.msg)
msg := proto.Clone(test.msg)
msg.Reset()
if n, err := ReadDelimited(bytes.NewBuffer(test.buf), msg); n != test.n || err != test.err {
t.Fatalf("ReadDelimited(%v, msg) = %v, %v; want %v, %v", test.buf, n, err, test.n, test.err)
}
if !Equal(msg, test.msg) {
if !proto.Equal(msg, test.msg) {
t.Fatalf("ReadDelimited(%v, msg); msg = %v; want %v", test.buf, msg, test.msg)
}
}
@ -137,12 +138,12 @@ I expect it may. Let's hope you enjoy testing as much as we do.`),
func TestEndToEndValid(t *testing.T) {
t.Parallel()
for _, test := range [][]Message{
for _, test := range [][]proto.Message{
{&Empty{}},
{&GoEnum{Foo: FOO_FOO1.Enum()}, &Empty{}, &GoEnum{Foo: FOO_FOO1.Enum()}},
{&GoEnum{Foo: FOO_FOO1.Enum()}},
{&Strings{
StringField: String(`This is my gigantic, unhappy string. It exceeds
StringField: proto.String(`This is my gigantic, unhappy string. It exceeds
the encoding size of a single byte varint. We are using it to fuzz test the
correctness of the header decoding mechanisms, which may prove problematic.
I expect it may. Let's hope you enjoy testing as much as we do.`),
@ -161,12 +162,12 @@ I expect it may. Let's hope you enjoy testing as much as we do.`),
}
var read int
for i, msg := range test {
out := Clone(msg)
out := proto.Clone(msg)
out.Reset()
n, _ := ReadDelimited(&buf, out)
// Decide to do EOF checking?
read += n
if !Equal(out, msg) {
if !proto.Equal(out, msg) {
t.Fatalf("out = %v; want %v[%d] = %#v", out, test, i, msg)
}
}

View file

@ -1,103 +0,0 @@
// Copyright 2010 The Go Authors. All rights reserved.
// http://github.com/golang/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package pbutil
import (
. "github.com/golang/protobuf/proto"
. "github.com/golang/protobuf/proto/testdata"
)
// FROM https://github.com/golang/protobuf/blob/master/proto/all_test.go.
func initGoTestField() *GoTestField {
f := new(GoTestField)
f.Label = String("label")
f.Type = String("type")
return f
}
// These are all structurally equivalent but the tag numbers differ.
// (It's remarkable that required, optional, and repeated all have
// 8 letters.)
func initGoTest_RequiredGroup() *GoTest_RequiredGroup {
return &GoTest_RequiredGroup{
RequiredField: String("required"),
}
}
func initGoTest_OptionalGroup() *GoTest_OptionalGroup {
return &GoTest_OptionalGroup{
RequiredField: String("optional"),
}
}
func initGoTest_RepeatedGroup() *GoTest_RepeatedGroup {
return &GoTest_RepeatedGroup{
RequiredField: String("repeated"),
}
}
func initGoTest(setdefaults bool) *GoTest {
pb := new(GoTest)
if setdefaults {
pb.F_BoolDefaulted = Bool(Default_GoTest_F_BoolDefaulted)
pb.F_Int32Defaulted = Int32(Default_GoTest_F_Int32Defaulted)
pb.F_Int64Defaulted = Int64(Default_GoTest_F_Int64Defaulted)
pb.F_Fixed32Defaulted = Uint32(Default_GoTest_F_Fixed32Defaulted)
pb.F_Fixed64Defaulted = Uint64(Default_GoTest_F_Fixed64Defaulted)
pb.F_Uint32Defaulted = Uint32(Default_GoTest_F_Uint32Defaulted)
pb.F_Uint64Defaulted = Uint64(Default_GoTest_F_Uint64Defaulted)
pb.F_FloatDefaulted = Float32(Default_GoTest_F_FloatDefaulted)
pb.F_DoubleDefaulted = Float64(Default_GoTest_F_DoubleDefaulted)
pb.F_StringDefaulted = String(Default_GoTest_F_StringDefaulted)
pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted
pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted)
pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted)
}
pb.Kind = GoTest_TIME.Enum()
pb.RequiredField = initGoTestField()
pb.F_BoolRequired = Bool(true)
pb.F_Int32Required = Int32(3)
pb.F_Int64Required = Int64(6)
pb.F_Fixed32Required = Uint32(32)
pb.F_Fixed64Required = Uint64(64)
pb.F_Uint32Required = Uint32(3232)
pb.F_Uint64Required = Uint64(6464)
pb.F_FloatRequired = Float32(3232)
pb.F_DoubleRequired = Float64(6464)
pb.F_StringRequired = String("string")
pb.F_BytesRequired = []byte("bytes")
pb.F_Sint32Required = Int32(-32)
pb.F_Sint64Required = Int64(-64)
pb.Requiredgroup = initGoTest_RequiredGroup()
return pb
}

View file

@ -2,9 +2,10 @@ sudo: false
language: go
go:
- 1.7.x
- 1.8.x
- 1.9.x
- 1.7.x # See README.md for current minimum version.
- 1.8.x
- 1.9.x
- 1.10.x
script:
- go test -short ./...
- go test -short ./...

View file

@ -16,3 +16,5 @@ Prometheus uses GitHub to manage reviews of pull requests.
and the _Formatting and style_ section of Peter Bourgon's [Go: Best
Practices for Production
Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style).
* Be sure to sign off on the [DCO](https://github.com/probot/dco#how-it-works)

View file

@ -1 +1,2 @@
* Björn Rabenstein <beorn@soundcloud.com>
* Krasi Georgiev <kgeorgie@redhat.com> for `api/...`
* Björn Rabenstein <beorn@soundcloud.com> for everything else

View file

@ -17,8 +17,12 @@ type goCollector struct {
metrics memStatsMetrics
}
// NewGoCollector returns a collector which exports metrics about the current
// go process.
// NewGoCollector returns a collector which exports metrics about the current Go
// process. This includes memory stats. To collect those, runtime.ReadMemStats
// is called. This causes a stop-the-world, which is very short with Go1.9+
// (~25µs). However, with older Go versions, the stop-the-world duration depends
// on the heap size and can be quite significant (~1.7 ms/GiB as per
// https://go-review.googlesource.com/c/go/+/34937).
func NewGoCollector() Collector {
return &goCollector{
goroutinesDesc: NewDesc(

View file

@ -38,12 +38,13 @@ const (
// Registerer and Gatherer interface a number of convenience functions in this
// package act on. Initially, both variables point to the same Registry, which
// has a process collector (currently on Linux only, see NewProcessCollector)
// and a Go collector (see NewGoCollector) already registered. This approach to
// keep default instances as global state mirrors the approach of other packages
// in the Go standard library. Note that there are caveats. Change the variables
// with caution and only if you understand the consequences. Users who want to
// avoid global state altogether should not use the convenience functions and
// act on custom instances instead.
// and a Go collector (see NewGoCollector, in particular the note about
// stop-the-world implication with Go versions older than 1.9) already
// registered. This approach to keep default instances as global state mirrors
// the approach of other packages in the Go standard library. Note that there
// are caveats. Change the variables with caution and only if you understand the
// consequences. Users who want to avoid global state altogether should not use
// the convenience functions and act on custom instances instead.
var (
defaultRegistry = NewRegistry()
DefaultRegisterer Registerer = defaultRegistry
@ -726,8 +727,8 @@ func checkMetricConsistency(
}
for _, labelPair := range dtoMetric.GetLabel() {
if !utf8.ValidString(*labelPair.Value) {
return fmt.Errorf("collected metric's label %s is not utf8: %#v", *labelPair.Name, *labelPair.Value)
if !utf8.ValidString(labelPair.GetValue()) {
return fmt.Errorf("collected metric's label %s is not utf8: %#v", labelPair.GetName(), labelPair.GetValue())
}
}

View file

@ -19,6 +19,8 @@ import (
type Client struct {
Conn
handleForwardsOnce sync.Once // guards calling (*Client).handleForwards
forwards forwardList // forwarded tcpip connections from the remote side
mu sync.Mutex
channelHandlers map[string]chan NewChannel
@ -60,8 +62,6 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
conn.Wait()
conn.forwards.closeAll()
}()
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip"))
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
return conn
}

View file

@ -32,6 +32,7 @@ type streamLocalChannelForwardMsg struct {
// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
c.handleForwardsOnce.Do(c.handleForwards)
m := streamLocalChannelForwardMsg{
socketPath,
}

View file

@ -90,10 +90,19 @@ type channelForwardMsg struct {
rport uint32
}
// handleForwards starts goroutines handling forwarded connections.
// It's called on first use by (*Client).ListenTCP to not launch
// goroutines until needed.
func (c *Client) handleForwards() {
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip"))
go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
}
// ListenTCP requests the remote peer open a listening socket
// on laddr. Incoming connections will be available by calling
// Accept on the returned net.Listener.
func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
c.handleForwardsOnce.Do(c.handleForwards)
if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
return c.autoPortListenWorkaround(laddr)
}

View file

@ -10,6 +10,7 @@ import (
"bytes"
"io"
"os"
"runtime"
"testing"
)
@ -326,6 +327,11 @@ func TestMakeRawState(t *testing.T) {
if err != nil {
t.Fatalf("failed to get terminal state from GetState: %s", err)
}
if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
t.Skip("MakeRaw not allowed on iOS; skipping test")
}
defer Restore(fd, st)
raw, err := MakeRaw(fd)
if err != nil {

View file

@ -17,19 +17,11 @@ import (
"golang.org/x/net/internal/sockstest"
)
const (
targetNetwork = "tcp6"
targetHostname = "fqdn.doesnotexist"
targetHostIP = "2001:db8::1"
targetPort = "5963"
)
func TestDial(t *testing.T) {
t.Run("Connect", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
@ -41,21 +33,45 @@ func TestDial(t *testing.T) {
Username: "username",
Password: "password",
}).Authenticate
c, err := d.Dial(targetNetwork, net.JoinHostPort(targetHostIP, targetPort))
if err == nil {
c.(*socks.Conn).BoundAddr()
c.Close()
}
c, err := d.DialContext(context.Background(), ss.TargetAddr().Network(), ss.TargetAddr().String())
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
c.(*socks.Conn).BoundAddr()
c.Close()
})
t.Run("ConnectWithConn", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired)
if err != nil {
t.Fatal(err)
}
defer ss.Close()
c, err := net.Dial(ss.Addr().Network(), ss.Addr().String())
if err != nil {
t.Fatal(err)
}
defer c.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
d.AuthMethods = []socks.AuthMethod{
socks.AuthMethodNotRequired,
socks.AuthMethodUsernamePassword,
}
d.Authenticate = (&socks.UsernamePassword{
Username: "username",
Password: "password",
}).Authenticate
a, err := d.DialWithConn(context.Background(), c, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err != nil {
t.Fatal(err)
}
if _, ok := a.(*socks.Addr); !ok {
t.Fatalf("got %+v; want socks.Addr", a)
}
})
t.Run("Cancel", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
@ -63,7 +79,7 @@ func TestDial(t *testing.T) {
defer cancel()
dialErr := make(chan error)
go func() {
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), net.JoinHostPort(targetHostname, targetPort))
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err == nil {
c.Close()
}
@ -73,41 +89,37 @@ func TestDial(t *testing.T) {
cancel()
err = <-dialErr
if perr, nerr := parseDialError(err); perr != context.Canceled && nerr == nil {
t.Errorf("got %v; want context.Canceled or equivalent", err)
return
t.Fatalf("got %v; want context.Canceled or equivalent", err)
}
})
t.Run("Deadline", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
defer cancel()
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), net.JoinHostPort(targetHostname, targetPort))
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err == nil {
c.Close()
}
if perr, nerr := parseDialError(err); perr != context.DeadlineExceeded && nerr == nil {
t.Errorf("got %v; want context.DeadlineExceeded or equivalent", err)
return
t.Fatalf("got %v; want context.DeadlineExceeded or equivalent", err)
}
})
t.Run("WithRogueServer", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, rogueCmdFunc)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
for i := 0; i < 2*len(rogueCmdList); i++ {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
defer cancel()
c, err := d.DialContext(ctx, targetNetwork, net.JoinHostPort(targetHostIP, targetPort))
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err == nil {
t.Log(c.(*socks.Conn).BoundAddr())
c.Close()

View file

@ -75,7 +75,7 @@ const (
AuthMethodNotRequired AuthMethod = 0x00 // no authentication required
AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password
AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authetication methods
AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
StatusSucceeded Reply = 0x00
)
@ -149,20 +149,13 @@ type Dialer struct {
// See func Dial of the net package of standard library for a
// description of the network and address parameters.
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
switch network {
case "tcp", "tcp6", "tcp4":
default:
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("network not implemented")}
}
switch d.cmd {
case CmdConnect, cmdBind:
default:
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("command not implemented")}
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
ctx = context.Background()
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
var err error
var c net.Conn
@ -185,11 +178,69 @@ func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.
return &Conn{Conn: c, boundAddr: a}, nil
}
// DialWithConn initiates a connection from SOCKS server to the target
// network and address using the connection c that is already
// connected to the SOCKS server.
//
// It returns the connection's local address assigned by the SOCKS
// server.
func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
a, err := d.connect(ctx, c, address)
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
return a, nil
}
// Dial connects to the provided address on the provided network.
//
// Deprecated: Use DialContext instead.
// Unlike DialContext, it returns a raw transport connection instead
// of a forward proxy connection.
//
// Deprecated: Use DialContext or DialWithConn instead.
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
return d.DialContext(context.Background(), network, address)
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
var err error
var c net.Conn
if d.ProxyDial != nil {
c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
} else {
c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
}
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
return nil, err
}
return c, nil
}
func (d *Dialer) validateTarget(network, address string) error {
switch network {
case "tcp", "tcp6", "tcp4":
default:
return errors.New("network not implemented")
}
switch d.cmd {
case CmdConnect, cmdBind:
default:
return errors.New("command not implemented")
}
return nil
}
func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {

Some files were not shown because too many files have changed in this diff Show more