mirror of https://github.com/docker/cli.git
Bump moby to d37f5c6bdf788a6cb82c07fb707e31a240eff5f9
Also bringing: . golang.org/x/net 5561cd9b4330353950f399814f427425c0a26fd2 . github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5 . github.com/docker/swarmkit bd69f6e8e301645afd344913fa1ede53a0a111fb . github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18 . github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e . github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 . github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 . github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8 . github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5 . github.com/matttproud/golang_protobuf_extensions v1.0.0 Signed-off-by: Mathieu Champlon <mathieu.champlon@docker.com>
This commit is contained in:
parent
6bab4a2a94
commit
5d54584f03
|
@ -412,9 +412,9 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
|
||||||
imageID := ""
|
imageID := ""
|
||||||
aux := func(auxJSON *json.RawMessage) {
|
aux := func(m jsonmessage.JSONMessage) {
|
||||||
var result types.BuildResult
|
var result types.BuildResult
|
||||||
if err := json.Unmarshal(*auxJSON, &result); err != nil {
|
if err := json.Unmarshal(*m.Aux, &result); err != nil {
|
||||||
fmt.Fprintf(dockerCli.Err(), "Failed to parse aux message: %s", err)
|
fmt.Fprintf(dockerCli.Err(), "Failed to parse aux message: %s", err)
|
||||||
} else {
|
} else {
|
||||||
imageID = result.ID
|
imageID = result.ID
|
||||||
|
|
|
@ -49,15 +49,15 @@ func PushTrustedReference(streams command.Streams, repoInfo *registry.Repository
|
||||||
// Count the times of calling for handleTarget,
|
// Count the times of calling for handleTarget,
|
||||||
// if it is called more that once, that should be considered an error in a trusted push.
|
// if it is called more that once, that should be considered an error in a trusted push.
|
||||||
cnt := 0
|
cnt := 0
|
||||||
handleTarget := func(aux *json.RawMessage) {
|
handleTarget := func(m jsonmessage.JSONMessage) {
|
||||||
cnt++
|
cnt++
|
||||||
if cnt > 1 {
|
if cnt > 1 {
|
||||||
// handleTarget should only be called one. This will be treated as an error.
|
// handleTarget should only be called once. This will be treated as an error.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var pushResult types.PushResult
|
var pushResult types.PushResult
|
||||||
err := json.Unmarshal(*aux, &pushResult)
|
err := json.Unmarshal(*m.Aux, &pushResult)
|
||||||
if err == nil && pushResult.Tag != "" {
|
if err == nil && pushResult.Tag != "" {
|
||||||
if dgst, err := digest.Parse(pushResult.Digest); err == nil {
|
if dgst, err := digest.Parse(pushResult.Digest); err == nil {
|
||||||
h, err := hex.DecodeString(dgst.Hex())
|
h, err := hex.DecodeString(dgst.Hex())
|
||||||
|
|
|
@ -11,14 +11,14 @@ import (
|
||||||
|
|
||||||
type fakeClient struct {
|
type fakeClient struct {
|
||||||
client.Client
|
client.Client
|
||||||
volumeCreateFunc func(volumetypes.VolumesCreateBody) (types.Volume, error)
|
volumeCreateFunc func(volumetypes.VolumeCreateBody) (types.Volume, error)
|
||||||
volumeInspectFunc func(volumeID string) (types.Volume, error)
|
volumeInspectFunc func(volumeID string) (types.Volume, error)
|
||||||
volumeListFunc func(filter filters.Args) (volumetypes.VolumesListOKBody, error)
|
volumeListFunc func(filter filters.Args) (volumetypes.VolumeListOKBody, error)
|
||||||
volumeRemoveFunc func(volumeID string, force bool) error
|
volumeRemoveFunc func(volumeID string, force bool) error
|
||||||
volumePruneFunc func(filter filters.Args) (types.VolumesPruneReport, error)
|
volumePruneFunc func(filter filters.Args) (types.VolumesPruneReport, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeClient) VolumeCreate(ctx context.Context, options volumetypes.VolumesCreateBody) (types.Volume, error) {
|
func (c *fakeClient) VolumeCreate(ctx context.Context, options volumetypes.VolumeCreateBody) (types.Volume, error) {
|
||||||
if c.volumeCreateFunc != nil {
|
if c.volumeCreateFunc != nil {
|
||||||
return c.volumeCreateFunc(options)
|
return c.volumeCreateFunc(options)
|
||||||
}
|
}
|
||||||
|
@ -32,11 +32,11 @@ func (c *fakeClient) VolumeInspect(ctx context.Context, volumeID string) (types.
|
||||||
return types.Volume{}, nil
|
return types.Volume{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeClient) VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
func (c *fakeClient) VolumeList(ctx context.Context, filter filters.Args) (volumetypes.VolumeListOKBody, error) {
|
||||||
if c.volumeListFunc != nil {
|
if c.volumeListFunc != nil {
|
||||||
return c.volumeListFunc(filter)
|
return c.volumeListFunc(filter)
|
||||||
}
|
}
|
||||||
return volumetypes.VolumesListOKBody{}, nil
|
return volumetypes.VolumeListOKBody{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeClient) VolumesPrune(ctx context.Context, filter filters.Args) (types.VolumesPruneReport, error) {
|
func (c *fakeClient) VolumesPrune(ctx context.Context, filter filters.Args) (types.VolumesPruneReport, error) {
|
||||||
|
|
|
@ -52,7 +52,7 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
func runCreate(dockerCli command.Cli, options createOptions) error {
|
func runCreate(dockerCli command.Cli, options createOptions) error {
|
||||||
client := dockerCli.Client()
|
client := dockerCli.Client()
|
||||||
|
|
||||||
volReq := volumetypes.VolumesCreateBody{
|
volReq := volumetypes.VolumeCreateBody{
|
||||||
Driver: options.driver,
|
Driver: options.driver,
|
||||||
DriverOpts: options.driverOpts.GetAll(),
|
DriverOpts: options.driverOpts.GetAll(),
|
||||||
Name: options.name,
|
Name: options.name,
|
||||||
|
|
|
@ -18,7 +18,7 @@ func TestVolumeCreateErrors(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
args []string
|
args []string
|
||||||
flags map[string]string
|
flags map[string]string
|
||||||
volumeCreateFunc func(volumetypes.VolumesCreateBody) (types.Volume, error)
|
volumeCreateFunc func(volumetypes.VolumeCreateBody) (types.Volume, error)
|
||||||
expectedError string
|
expectedError string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,7 @@ func TestVolumeCreateErrors(t *testing.T) {
|
||||||
expectedError: "requires at most 1 argument",
|
expectedError: "requires at most 1 argument",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
volumeCreateFunc: func(createBody volumetypes.VolumesCreateBody) (types.Volume, error) {
|
volumeCreateFunc: func(createBody volumetypes.VolumeCreateBody) (types.Volume, error) {
|
||||||
return types.Volume{}, errors.Errorf("error creating volume")
|
return types.Volume{}, errors.Errorf("error creating volume")
|
||||||
},
|
},
|
||||||
expectedError: "error creating volume",
|
expectedError: "error creating volume",
|
||||||
|
@ -57,7 +57,7 @@ func TestVolumeCreateErrors(t *testing.T) {
|
||||||
func TestVolumeCreateWithName(t *testing.T) {
|
func TestVolumeCreateWithName(t *testing.T) {
|
||||||
name := "foo"
|
name := "foo"
|
||||||
cli := test.NewFakeCli(&fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
volumeCreateFunc: func(body volumetypes.VolumesCreateBody) (types.Volume, error) {
|
volumeCreateFunc: func(body volumetypes.VolumeCreateBody) (types.Volume, error) {
|
||||||
if body.Name != name {
|
if body.Name != name {
|
||||||
return types.Volume{}, errors.Errorf("expected name %q, got %q", name, body.Name)
|
return types.Volume{}, errors.Errorf("expected name %q, got %q", name, body.Name)
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ func TestVolumeCreateWithFlags(t *testing.T) {
|
||||||
name := "banana"
|
name := "banana"
|
||||||
|
|
||||||
cli := test.NewFakeCli(&fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
volumeCreateFunc: func(body volumetypes.VolumesCreateBody) (types.Volume, error) {
|
volumeCreateFunc: func(body volumetypes.VolumeCreateBody) (types.Volume, error) {
|
||||||
if body.Name != "" {
|
if body.Name != "" {
|
||||||
return types.Volume{}, errors.Errorf("expected empty name, got %q", body.Name)
|
return types.Volume{}, errors.Errorf("expected empty name, got %q", body.Name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ func TestVolumeListErrors(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
args []string
|
args []string
|
||||||
flags map[string]string
|
flags map[string]string
|
||||||
volumeListFunc func(filter filters.Args) (volumetypes.VolumesListOKBody, error)
|
volumeListFunc func(filter filters.Args) (volumetypes.VolumeListOKBody, error)
|
||||||
expectedError string
|
expectedError string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -28,8 +28,8 @@ func TestVolumeListErrors(t *testing.T) {
|
||||||
expectedError: "accepts no argument",
|
expectedError: "accepts no argument",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
volumeListFunc: func(filter filters.Args) (volumetypes.VolumeListOKBody, error) {
|
||||||
return volumetypes.VolumesListOKBody{}, errors.Errorf("error listing volumes")
|
return volumetypes.VolumeListOKBody{}, errors.Errorf("error listing volumes")
|
||||||
},
|
},
|
||||||
expectedError: "error listing volumes",
|
expectedError: "error listing volumes",
|
||||||
},
|
},
|
||||||
|
@ -51,8 +51,8 @@ func TestVolumeListErrors(t *testing.T) {
|
||||||
|
|
||||||
func TestVolumeListWithoutFormat(t *testing.T) {
|
func TestVolumeListWithoutFormat(t *testing.T) {
|
||||||
cli := test.NewFakeCli(&fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
volumeListFunc: func(filter filters.Args) (volumetypes.VolumeListOKBody, error) {
|
||||||
return volumetypes.VolumesListOKBody{
|
return volumetypes.VolumeListOKBody{
|
||||||
Volumes: []*types.Volume{
|
Volumes: []*types.Volume{
|
||||||
Volume(),
|
Volume(),
|
||||||
Volume(VolumeName("foo"), VolumeDriver("bar")),
|
Volume(VolumeName("foo"), VolumeDriver("bar")),
|
||||||
|
@ -70,8 +70,8 @@ func TestVolumeListWithoutFormat(t *testing.T) {
|
||||||
|
|
||||||
func TestVolumeListWithConfigFormat(t *testing.T) {
|
func TestVolumeListWithConfigFormat(t *testing.T) {
|
||||||
cli := test.NewFakeCli(&fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
volumeListFunc: func(filter filters.Args) (volumetypes.VolumeListOKBody, error) {
|
||||||
return volumetypes.VolumesListOKBody{
|
return volumetypes.VolumeListOKBody{
|
||||||
Volumes: []*types.Volume{
|
Volumes: []*types.Volume{
|
||||||
Volume(),
|
Volume(),
|
||||||
Volume(VolumeName("foo"), VolumeDriver("bar")),
|
Volume(VolumeName("foo"), VolumeDriver("bar")),
|
||||||
|
@ -92,8 +92,8 @@ func TestVolumeListWithConfigFormat(t *testing.T) {
|
||||||
|
|
||||||
func TestVolumeListWithFormat(t *testing.T) {
|
func TestVolumeListWithFormat(t *testing.T) {
|
||||||
cli := test.NewFakeCli(&fakeClient{
|
cli := test.NewFakeCli(&fakeClient{
|
||||||
volumeListFunc: func(filter filters.Args) (volumetypes.VolumesListOKBody, error) {
|
volumeListFunc: func(filter filters.Args) (volumetypes.VolumeListOKBody, error) {
|
||||||
return volumetypes.VolumesListOKBody{
|
return volumetypes.VolumeListOKBody{
|
||||||
Volumes: []*types.Volume{
|
Volumes: []*types.Volume{
|
||||||
Volume(),
|
Volume(),
|
||||||
Volume(VolumeName("foo"), VolumeDriver("bar")),
|
Volume(VolumeName("foo"), VolumeDriver("bar")),
|
||||||
|
|
|
@ -133,7 +133,7 @@ func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Na
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to parse repo name from %s", ref)
|
return nil, errors.Wrapf(err, "failed to parse repo name from %s", ref)
|
||||||
}
|
}
|
||||||
return distributionclient.NewRepository(ctx, repoName, repoEndpoint.BaseURL(), httpTransport)
|
return distributionclient.NewRepository(repoName, repoEndpoint.BaseURL(), httpTransport)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) getHTTPTransportForRepoEndpoint(ctx context.Context, repoEndpoint repositoryEndpoint) (http.RoundTripper, error) {
|
func (c *client) getHTTPTransportForRepoEndpoint(ctx context.Context, repoEndpoint repositoryEndpoint) (http.RoundTripper, error) {
|
||||||
|
|
15
vendor.conf
15
vendor.conf
|
@ -1,19 +1,21 @@
|
||||||
github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
|
github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
|
||||||
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
|
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||||
|
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||||
github.com/containerd/continuity d8fb8589b0e8e85b8c8bbaa8840226d0dfeb7371
|
github.com/containerd/continuity d8fb8589b0e8e85b8c8bbaa8840226d0dfeb7371
|
||||||
github.com/coreos/etcd v3.2.1
|
github.com/coreos/etcd v3.2.1
|
||||||
github.com/cpuguy83/go-md2man v1.0.8
|
github.com/cpuguy83/go-md2man v1.0.8
|
||||||
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
|
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
|
||||||
github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
|
github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5
|
||||||
github.com/docker/docker ed7b6428c133e7c59404251a09b7d6b02fa83cc2
|
github.com/docker/docker d37f5c6bdf788a6cb82c07fb707e31a240eff5f9
|
||||||
github.com/docker/docker-credential-helpers 3c90bd29a46b943b2a9842987b58fb91a7c1819b
|
github.com/docker/docker-credential-helpers 3c90bd29a46b943b2a9842987b58fb91a7c1819b
|
||||||
# the docker/go package contains a customized version of canonical/json
|
# 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.
|
# and is used by Notary. The package is periodically rebased on current Go versions.
|
||||||
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
|
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
|
||||||
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
|
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
|
||||||
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||||
|
github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
|
||||||
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
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 ff4f55a206334ef123e4f79bbf348980da81ca46
|
||||||
github.com/emicklei/go-restful-swagger12 dcef7f55730566d41eae5db10e7d6981829720f6
|
github.com/emicklei/go-restful-swagger12 dcef7f55730566d41eae5db10e7d6981829720f6
|
||||||
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
|
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
|
||||||
|
@ -41,6 +43,7 @@ github.com/juju/ratelimit 5b9ff866471762aa2ab2dced63c9fb6f53921342
|
||||||
github.com/json-iterator/go 6240e1e7983a85228f7fd9c3e1b6932d46ec58e2
|
github.com/json-iterator/go 6240e1e7983a85228f7fd9c3e1b6932d46ec58e2
|
||||||
github.com/mailru/easyjson d5b7844b561a7bc640052f1b935f7b800330d7e0
|
github.com/mailru/easyjson d5b7844b561a7bc640052f1b935f7b800330d7e0
|
||||||
github.com/mattn/go-shellwords v1.0.3
|
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/Microsoft/go-winio v0.4.6
|
||||||
github.com/miekg/pkcs11 5f6e0d0dad6f472df908c8e968a98ef00c9224bb
|
github.com/miekg/pkcs11 5f6e0d0dad6f472df908c8e968a98ef00c9224bb
|
||||||
github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715
|
github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715
|
||||||
|
@ -52,6 +55,10 @@ github.com/opencontainers/runc 4fc53a81fb7c994640722ac585fa9ca548971871
|
||||||
github.com/peterbourgon/diskv 5f041e8faa004a95c88a202771f4cc3e991971e6
|
github.com/peterbourgon/diskv 5f041e8faa004a95c88a202771f4cc3e991971e6
|
||||||
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
|
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
|
||||||
github.com/pmezard/go-difflib v1.0.0
|
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/purell 8a290539e2e8629dbc4e6bad948158f790ec31f4
|
||||||
github.com/PuerkitoBio/urlesc 5bd2802263f21d8788851d5305584c82a5c75d7e
|
github.com/PuerkitoBio/urlesc 5bd2802263f21d8788851d5305584c82a5c75d7e
|
||||||
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
|
github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
|
||||||
|
@ -65,7 +72,7 @@ github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
|
||||||
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
|
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
|
||||||
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
|
github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d
|
||||||
golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
|
golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
|
||||||
golang.org/x/net a8b9294777976932365dabb6640cf1468d95c70f
|
golang.org/x/net 5561cd9b4330353950f399814f427425c0a26fd2
|
||||||
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
|
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
|
||||||
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
|
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
|
||||||
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
|
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
Copyright (C) 2013 Blake Mizerany
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Perks for Go (golang.org)
|
||||||
|
|
||||||
|
Perks contains the Go package quantile that computes approximate quantiles over
|
||||||
|
an unbounded data stream within low memory and CPU bounds.
|
||||||
|
|
||||||
|
For more information and examples, see:
|
||||||
|
http://godoc.org/github.com/bmizerany/perks
|
||||||
|
|
||||||
|
A very special thank you and shout out to Graham Cormode (Rutgers University),
|
||||||
|
Flip Korn (AT&T Labs–Research), S. Muthukrishnan (Rutgers University), and
|
||||||
|
Divesh Srivastava (AT&T Labs–Research) for their research and publication of
|
||||||
|
[Effective Computation of Biased Quantiles over Data Streams](http://www.cs.rutgers.edu/~muthu/bquant.pdf)
|
||||||
|
|
||||||
|
Thank you, also:
|
||||||
|
* Armon Dadgar (@armon)
|
||||||
|
* Andrew Gerrand (@nf)
|
||||||
|
* Brad Fitzpatrick (@bradfitz)
|
||||||
|
* Keith Rarick (@kr)
|
||||||
|
|
||||||
|
FAQ:
|
||||||
|
|
||||||
|
Q: Why not move the quantile package into the project root?
|
||||||
|
A: I want to add more packages to perks later.
|
||||||
|
|
||||||
|
Copyright (C) 2013 Blake Mizerany
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,292 @@
|
||||||
|
// Package quantile computes approximate quantiles over an unbounded data
|
||||||
|
// stream within low memory and CPU bounds.
|
||||||
|
//
|
||||||
|
// A small amount of accuracy is traded to achieve the above properties.
|
||||||
|
//
|
||||||
|
// Multiple streams can be merged before calling Query to generate a single set
|
||||||
|
// of results. This is meaningful when the streams represent the same type of
|
||||||
|
// data. See Merge and Samples.
|
||||||
|
//
|
||||||
|
// For more detailed information about the algorithm used, see:
|
||||||
|
//
|
||||||
|
// Effective Computation of Biased Quantiles over Data Streams
|
||||||
|
//
|
||||||
|
// http://www.cs.rutgers.edu/~muthu/bquant.pdf
|
||||||
|
package quantile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sample holds an observed value and meta information for compression. JSON
|
||||||
|
// tags have been added for convenience.
|
||||||
|
type Sample struct {
|
||||||
|
Value float64 `json:",string"`
|
||||||
|
Width float64 `json:",string"`
|
||||||
|
Delta float64 `json:",string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samples represents a slice of samples. It implements sort.Interface.
|
||||||
|
type Samples []Sample
|
||||||
|
|
||||||
|
func (a Samples) Len() int { return len(a) }
|
||||||
|
func (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value }
|
||||||
|
func (a Samples) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
|
||||||
|
type invariant func(s *stream, r float64) float64
|
||||||
|
|
||||||
|
// NewLowBiased returns an initialized Stream for low-biased quantiles
|
||||||
|
// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
|
||||||
|
// error guarantees can still be given even for the lower ranks of the data
|
||||||
|
// distribution.
|
||||||
|
//
|
||||||
|
// The provided epsilon is a relative error, i.e. the true quantile of a value
|
||||||
|
// returned by a query is guaranteed to be within (1±Epsilon)*Quantile.
|
||||||
|
//
|
||||||
|
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
|
||||||
|
// properties.
|
||||||
|
func NewLowBiased(epsilon float64) *Stream {
|
||||||
|
ƒ := func(s *stream, r float64) float64 {
|
||||||
|
return 2 * epsilon * r
|
||||||
|
}
|
||||||
|
return newStream(ƒ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHighBiased returns an initialized Stream for high-biased quantiles
|
||||||
|
// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
|
||||||
|
// error guarantees can still be given even for the higher ranks of the data
|
||||||
|
// distribution.
|
||||||
|
//
|
||||||
|
// The provided epsilon is a relative error, i.e. the true quantile of a value
|
||||||
|
// returned by a query is guaranteed to be within 1-(1±Epsilon)*(1-Quantile).
|
||||||
|
//
|
||||||
|
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
|
||||||
|
// properties.
|
||||||
|
func NewHighBiased(epsilon float64) *Stream {
|
||||||
|
ƒ := func(s *stream, r float64) float64 {
|
||||||
|
return 2 * epsilon * (s.n - r)
|
||||||
|
}
|
||||||
|
return newStream(ƒ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTargeted returns an initialized Stream concerned with a particular set of
|
||||||
|
// quantile values that are supplied a priori. Knowing these a priori reduces
|
||||||
|
// space and computation time. The targets map maps the desired quantiles to
|
||||||
|
// their absolute errors, i.e. the true quantile of a value returned by a query
|
||||||
|
// is guaranteed to be within (Quantile±Epsilon).
|
||||||
|
//
|
||||||
|
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties.
|
||||||
|
func NewTargeted(targets map[float64]float64) *Stream {
|
||||||
|
ƒ := func(s *stream, r float64) float64 {
|
||||||
|
var m = math.MaxFloat64
|
||||||
|
var f float64
|
||||||
|
for quantile, epsilon := range targets {
|
||||||
|
if quantile*s.n <= r {
|
||||||
|
f = (2 * epsilon * r) / quantile
|
||||||
|
} else {
|
||||||
|
f = (2 * epsilon * (s.n - r)) / (1 - quantile)
|
||||||
|
}
|
||||||
|
if f < m {
|
||||||
|
m = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
return newStream(ƒ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stream computes quantiles for a stream of float64s. It is not thread-safe by
|
||||||
|
// design. Take care when using across multiple goroutines.
|
||||||
|
type Stream struct {
|
||||||
|
*stream
|
||||||
|
b Samples
|
||||||
|
sorted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStream(ƒ invariant) *Stream {
|
||||||
|
x := &stream{ƒ: ƒ}
|
||||||
|
return &Stream{x, make(Samples, 0, 500), true}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert inserts v into the stream.
|
||||||
|
func (s *Stream) Insert(v float64) {
|
||||||
|
s.insert(Sample{Value: v, Width: 1})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) insert(sample Sample) {
|
||||||
|
s.b = append(s.b, sample)
|
||||||
|
s.sorted = false
|
||||||
|
if len(s.b) == cap(s.b) {
|
||||||
|
s.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query returns the computed qth percentiles value. If s was created with
|
||||||
|
// NewTargeted, and q is not in the set of quantiles provided a priori, Query
|
||||||
|
// will return an unspecified result.
|
||||||
|
func (s *Stream) Query(q float64) float64 {
|
||||||
|
if !s.flushed() {
|
||||||
|
// Fast path when there hasn't been enough data for a flush;
|
||||||
|
// this also yields better accuracy for small sets of data.
|
||||||
|
l := len(s.b)
|
||||||
|
if l == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
i := int(math.Ceil(float64(l) * q))
|
||||||
|
if i > 0 {
|
||||||
|
i -= 1
|
||||||
|
}
|
||||||
|
s.maybeSort()
|
||||||
|
return s.b[i].Value
|
||||||
|
}
|
||||||
|
s.flush()
|
||||||
|
return s.stream.query(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge merges samples into the underlying streams samples. This is handy when
|
||||||
|
// merging multiple streams from separate threads, database shards, etc.
|
||||||
|
//
|
||||||
|
// ATTENTION: This method is broken and does not yield correct results. The
|
||||||
|
// underlying algorithm is not capable of merging streams correctly.
|
||||||
|
func (s *Stream) Merge(samples Samples) {
|
||||||
|
sort.Sort(samples)
|
||||||
|
s.stream.merge(samples)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset reinitializes and clears the list reusing the samples buffer memory.
|
||||||
|
func (s *Stream) Reset() {
|
||||||
|
s.stream.reset()
|
||||||
|
s.b = s.b[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samples returns stream samples held by s.
|
||||||
|
func (s *Stream) Samples() Samples {
|
||||||
|
if !s.flushed() {
|
||||||
|
return s.b
|
||||||
|
}
|
||||||
|
s.flush()
|
||||||
|
return s.stream.samples()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns the total number of samples observed in the stream
|
||||||
|
// since initialization.
|
||||||
|
func (s *Stream) Count() int {
|
||||||
|
return len(s.b) + s.stream.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) flush() {
|
||||||
|
s.maybeSort()
|
||||||
|
s.stream.merge(s.b)
|
||||||
|
s.b = s.b[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) maybeSort() {
|
||||||
|
if !s.sorted {
|
||||||
|
s.sorted = true
|
||||||
|
sort.Sort(s.b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) flushed() bool {
|
||||||
|
return len(s.stream.l) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type stream struct {
|
||||||
|
n float64
|
||||||
|
l []Sample
|
||||||
|
ƒ invariant
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) reset() {
|
||||||
|
s.l = s.l[:0]
|
||||||
|
s.n = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) insert(v float64) {
|
||||||
|
s.merge(Samples{{v, 1, 0}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) merge(samples Samples) {
|
||||||
|
// TODO(beorn7): This tries to merge not only individual samples, but
|
||||||
|
// whole summaries. The paper doesn't mention merging summaries at
|
||||||
|
// all. Unittests show that the merging is inaccurate. Find out how to
|
||||||
|
// do merges properly.
|
||||||
|
var r float64
|
||||||
|
i := 0
|
||||||
|
for _, sample := range samples {
|
||||||
|
for ; i < len(s.l); i++ {
|
||||||
|
c := s.l[i]
|
||||||
|
if c.Value > sample.Value {
|
||||||
|
// Insert at position i.
|
||||||
|
s.l = append(s.l, Sample{})
|
||||||
|
copy(s.l[i+1:], s.l[i:])
|
||||||
|
s.l[i] = Sample{
|
||||||
|
sample.Value,
|
||||||
|
sample.Width,
|
||||||
|
math.Max(sample.Delta, math.Floor(s.ƒ(s, r))-1),
|
||||||
|
// TODO(beorn7): How to calculate delta correctly?
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
goto inserted
|
||||||
|
}
|
||||||
|
r += c.Width
|
||||||
|
}
|
||||||
|
s.l = append(s.l, Sample{sample.Value, sample.Width, 0})
|
||||||
|
i++
|
||||||
|
inserted:
|
||||||
|
s.n += sample.Width
|
||||||
|
r += sample.Width
|
||||||
|
}
|
||||||
|
s.compress()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) count() int {
|
||||||
|
return int(s.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) query(q float64) float64 {
|
||||||
|
t := math.Ceil(q * s.n)
|
||||||
|
t += math.Ceil(s.ƒ(s, t) / 2)
|
||||||
|
p := s.l[0]
|
||||||
|
var r float64
|
||||||
|
for _, c := range s.l[1:] {
|
||||||
|
r += p.Width
|
||||||
|
if r+c.Width+c.Delta > t {
|
||||||
|
return p.Value
|
||||||
|
}
|
||||||
|
p = c
|
||||||
|
}
|
||||||
|
return p.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) compress() {
|
||||||
|
if len(s.l) < 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
x := s.l[len(s.l)-1]
|
||||||
|
xi := len(s.l) - 1
|
||||||
|
r := s.n - 1 - x.Width
|
||||||
|
|
||||||
|
for i := len(s.l) - 2; i >= 0; i-- {
|
||||||
|
c := s.l[i]
|
||||||
|
if c.Width+x.Width+x.Delta <= s.ƒ(s, r) {
|
||||||
|
x.Width += c.Width
|
||||||
|
s.l[xi] = x
|
||||||
|
// Remove element at i.
|
||||||
|
copy(s.l[i:], s.l[i+1:])
|
||||||
|
s.l = s.l[:len(s.l)-1]
|
||||||
|
xi -= 1
|
||||||
|
} else {
|
||||||
|
x = c
|
||||||
|
xi = i
|
||||||
|
}
|
||||||
|
r -= c.Width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) samples() Samples {
|
||||||
|
samples := make(Samples, len(s.l))
|
||||||
|
copy(samples, s.l)
|
||||||
|
return samples
|
||||||
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
package distribution
|
package distribution
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/distribution/context"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
package context
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/docker/distribution/uuid"
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Context is a copy of Context from the golang.org/x/net/context package.
|
|
||||||
type Context interface {
|
|
||||||
context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// instanceContext is a context that provides only an instance id. It is
|
|
||||||
// provided as the main background context.
|
|
||||||
type instanceContext struct {
|
|
||||||
Context
|
|
||||||
id string // id of context, logged as "instance.id"
|
|
||||||
once sync.Once // once protect generation of the id
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ic *instanceContext) Value(key interface{}) interface{} {
|
|
||||||
if key == "instance.id" {
|
|
||||||
ic.once.Do(func() {
|
|
||||||
// We want to lazy initialize the UUID such that we don't
|
|
||||||
// call a random generator from the package initialization
|
|
||||||
// code. For various reasons random could not be available
|
|
||||||
// https://github.com/docker/distribution/issues/782
|
|
||||||
ic.id = uuid.Generate().String()
|
|
||||||
})
|
|
||||||
return ic.id
|
|
||||||
}
|
|
||||||
|
|
||||||
return ic.Context.Value(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
var background = &instanceContext{
|
|
||||||
Context: context.Background(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Background returns a non-nil, empty Context. The background context
|
|
||||||
// provides a single key, "instance.id" that is globally unique to the
|
|
||||||
// process.
|
|
||||||
func Background() Context {
|
|
||||||
return background
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithValue returns a copy of parent in which the value associated with key is
|
|
||||||
// val. Use context Values only for request-scoped data that transits processes
|
|
||||||
// and APIs, not for passing optional parameters to functions.
|
|
||||||
func WithValue(parent Context, key, val interface{}) Context {
|
|
||||||
return context.WithValue(parent, key, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// stringMapContext is a simple context implementation that checks a map for a
|
|
||||||
// key, falling back to a parent if not present.
|
|
||||||
type stringMapContext struct {
|
|
||||||
context.Context
|
|
||||||
m map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithValues returns a context that proxies lookups through a map. Only
|
|
||||||
// supports string keys.
|
|
||||||
func WithValues(ctx context.Context, m map[string]interface{}) context.Context {
|
|
||||||
mo := make(map[string]interface{}, len(m)) // make our own copy.
|
|
||||||
for k, v := range m {
|
|
||||||
mo[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringMapContext{
|
|
||||||
Context: ctx,
|
|
||||||
m: mo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (smc stringMapContext) Value(key interface{}) interface{} {
|
|
||||||
if ks, ok := key.(string); ok {
|
|
||||||
if v, ok := smc.m[ks]; ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return smc.Context.Value(key)
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
// Package context provides several utilities for working with
|
|
||||||
// golang.org/x/net/context in http requests. Primarily, the focus is on
|
|
||||||
// logging relevant request information but this package is not limited to
|
|
||||||
// that purpose.
|
|
||||||
//
|
|
||||||
// The easiest way to get started is to get the background context:
|
|
||||||
//
|
|
||||||
// ctx := context.Background()
|
|
||||||
//
|
|
||||||
// The returned context should be passed around your application and be the
|
|
||||||
// root of all other context instances. If the application has a version, this
|
|
||||||
// line should be called before anything else:
|
|
||||||
//
|
|
||||||
// ctx := context.WithVersion(context.Background(), version)
|
|
||||||
//
|
|
||||||
// The above will store the version in the context and will be available to
|
|
||||||
// the logger.
|
|
||||||
//
|
|
||||||
// Logging
|
|
||||||
//
|
|
||||||
// The most useful aspect of this package is GetLogger. This function takes
|
|
||||||
// any context.Context interface and returns the current logger from the
|
|
||||||
// context. Canonical usage looks like this:
|
|
||||||
//
|
|
||||||
// GetLogger(ctx).Infof("something interesting happened")
|
|
||||||
//
|
|
||||||
// GetLogger also takes optional key arguments. The keys will be looked up in
|
|
||||||
// the context and reported with the logger. The following example would
|
|
||||||
// return a logger that prints the version with each log message:
|
|
||||||
//
|
|
||||||
// ctx := context.Context(context.Background(), "version", version)
|
|
||||||
// GetLogger(ctx, "version").Infof("this log message has a version field")
|
|
||||||
//
|
|
||||||
// The above would print out a log message like this:
|
|
||||||
//
|
|
||||||
// INFO[0000] this log message has a version field version=v2.0.0-alpha.2.m
|
|
||||||
//
|
|
||||||
// When used with WithLogger, we gain the ability to decorate the context with
|
|
||||||
// loggers that have information from disparate parts of the call stack.
|
|
||||||
// Following from the version example, we can build a new context with the
|
|
||||||
// configured logger such that we always print the version field:
|
|
||||||
//
|
|
||||||
// ctx = WithLogger(ctx, GetLogger(ctx, "version"))
|
|
||||||
//
|
|
||||||
// Since the logger has been pushed to the context, we can now get the version
|
|
||||||
// field for free with our log messages. Future calls to GetLogger on the new
|
|
||||||
// context will have the version field:
|
|
||||||
//
|
|
||||||
// GetLogger(ctx).Infof("this log message has a version field")
|
|
||||||
//
|
|
||||||
// This becomes more powerful when we start stacking loggers. Let's say we
|
|
||||||
// have the version logger from above but also want a request id. Using the
|
|
||||||
// context above, in our request scoped function, we place another logger in
|
|
||||||
// the context:
|
|
||||||
//
|
|
||||||
// ctx = context.WithValue(ctx, "http.request.id", "unique id") // called when building request context
|
|
||||||
// ctx = WithLogger(ctx, GetLogger(ctx, "http.request.id"))
|
|
||||||
//
|
|
||||||
// When GetLogger is called on the new context, "http.request.id" will be
|
|
||||||
// included as a logger field, along with the original "version" field:
|
|
||||||
//
|
|
||||||
// INFO[0000] this log message has a version field http.request.id=unique id version=v2.0.0-alpha.2.m
|
|
||||||
//
|
|
||||||
// Note that this only affects the new context, the previous context, with the
|
|
||||||
// version field, can be used independently. Put another way, the new logger,
|
|
||||||
// added to the request context, is unique to that context and can have
|
|
||||||
// request scoped variables.
|
|
||||||
//
|
|
||||||
// HTTP Requests
|
|
||||||
//
|
|
||||||
// This package also contains several methods for working with http requests.
|
|
||||||
// The concepts are very similar to those described above. We simply place the
|
|
||||||
// request in the context using WithRequest. This makes the request variables
|
|
||||||
// available. GetRequestLogger can then be called to get request specific
|
|
||||||
// variables in a log line:
|
|
||||||
//
|
|
||||||
// ctx = WithRequest(ctx, req)
|
|
||||||
// GetRequestLogger(ctx).Infof("request variables")
|
|
||||||
//
|
|
||||||
// Like above, if we want to include the request data in all log messages in
|
|
||||||
// the context, we push the logger to a new context and use that one:
|
|
||||||
//
|
|
||||||
// ctx = WithLogger(ctx, GetRequestLogger(ctx))
|
|
||||||
//
|
|
||||||
// The concept is fairly powerful and ensures that calls throughout the stack
|
|
||||||
// can be traced in log messages. Using the fields like "http.request.id", one
|
|
||||||
// can analyze call flow for a particular request with a simple grep of the
|
|
||||||
// logs.
|
|
||||||
package context
|
|
|
@ -1,366 +0,0 @@
|
||||||
package context
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/docker/distribution/uuid"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Common errors used with this package.
|
|
||||||
var (
|
|
||||||
ErrNoRequestContext = errors.New("no http request in context")
|
|
||||||
ErrNoResponseWriterContext = errors.New("no http response in context")
|
|
||||||
)
|
|
||||||
|
|
||||||
func parseIP(ipStr string) net.IP {
|
|
||||||
ip := net.ParseIP(ipStr)
|
|
||||||
if ip == nil {
|
|
||||||
log.Warnf("invalid remote IP address: %q", ipStr)
|
|
||||||
}
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteAddr extracts the remote address of the request, taking into
|
|
||||||
// account proxy headers.
|
|
||||||
func RemoteAddr(r *http.Request) string {
|
|
||||||
if prior := r.Header.Get("X-Forwarded-For"); prior != "" {
|
|
||||||
proxies := strings.Split(prior, ",")
|
|
||||||
if len(proxies) > 0 {
|
|
||||||
remoteAddr := strings.Trim(proxies[0], " ")
|
|
||||||
if parseIP(remoteAddr) != nil {
|
|
||||||
return remoteAddr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// X-Real-Ip is less supported, but worth checking in the
|
|
||||||
// absence of X-Forwarded-For
|
|
||||||
if realIP := r.Header.Get("X-Real-Ip"); realIP != "" {
|
|
||||||
if parseIP(realIP) != nil {
|
|
||||||
return realIP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.RemoteAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteIP extracts the remote IP of the request, taking into
|
|
||||||
// account proxy headers.
|
|
||||||
func RemoteIP(r *http.Request) string {
|
|
||||||
addr := RemoteAddr(r)
|
|
||||||
|
|
||||||
// Try parsing it as "IP:port"
|
|
||||||
if ip, _, err := net.SplitHostPort(addr); err == nil {
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithRequest places the request on the context. The context of the request
|
|
||||||
// is assigned a unique id, available at "http.request.id". The request itself
|
|
||||||
// is available at "http.request". Other common attributes are available under
|
|
||||||
// the prefix "http.request.". If a request is already present on the context,
|
|
||||||
// this method will panic.
|
|
||||||
func WithRequest(ctx Context, r *http.Request) Context {
|
|
||||||
if ctx.Value("http.request") != nil {
|
|
||||||
// NOTE(stevvooe): This needs to be considered a programming error. It
|
|
||||||
// is unlikely that we'd want to have more than one request in
|
|
||||||
// context.
|
|
||||||
panic("only one request per context")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &httpRequestContext{
|
|
||||||
Context: ctx,
|
|
||||||
startedAt: time.Now(),
|
|
||||||
id: uuid.Generate().String(),
|
|
||||||
r: r,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRequest returns the http request in the given context. Returns
|
|
||||||
// ErrNoRequestContext if the context does not have an http request associated
|
|
||||||
// with it.
|
|
||||||
func GetRequest(ctx Context) (*http.Request, error) {
|
|
||||||
if r, ok := ctx.Value("http.request").(*http.Request); r != nil && ok {
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
return nil, ErrNoRequestContext
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRequestID attempts to resolve the current request id, if possible. An
|
|
||||||
// error is return if it is not available on the context.
|
|
||||||
func GetRequestID(ctx Context) string {
|
|
||||||
return GetStringValue(ctx, "http.request.id")
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithResponseWriter returns a new context and response writer that makes
|
|
||||||
// interesting response statistics available within the context.
|
|
||||||
func WithResponseWriter(ctx Context, w http.ResponseWriter) (Context, http.ResponseWriter) {
|
|
||||||
if closeNotifier, ok := w.(http.CloseNotifier); ok {
|
|
||||||
irwCN := &instrumentedResponseWriterCN{
|
|
||||||
instrumentedResponseWriter: instrumentedResponseWriter{
|
|
||||||
ResponseWriter: w,
|
|
||||||
Context: ctx,
|
|
||||||
},
|
|
||||||
CloseNotifier: closeNotifier,
|
|
||||||
}
|
|
||||||
|
|
||||||
return irwCN, irwCN
|
|
||||||
}
|
|
||||||
|
|
||||||
irw := instrumentedResponseWriter{
|
|
||||||
ResponseWriter: w,
|
|
||||||
Context: ctx,
|
|
||||||
}
|
|
||||||
return &irw, &irw
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetResponseWriter returns the http.ResponseWriter from the provided
|
|
||||||
// context. If not present, ErrNoResponseWriterContext is returned. The
|
|
||||||
// returned instance provides instrumentation in the context.
|
|
||||||
func GetResponseWriter(ctx Context) (http.ResponseWriter, error) {
|
|
||||||
v := ctx.Value("http.response")
|
|
||||||
|
|
||||||
rw, ok := v.(http.ResponseWriter)
|
|
||||||
if !ok || rw == nil {
|
|
||||||
return nil, ErrNoResponseWriterContext
|
|
||||||
}
|
|
||||||
|
|
||||||
return rw, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getVarsFromRequest let's us change request vars implementation for testing
|
|
||||||
// and maybe future changes.
|
|
||||||
var getVarsFromRequest = mux.Vars
|
|
||||||
|
|
||||||
// WithVars extracts gorilla/mux vars and makes them available on the returned
|
|
||||||
// context. Variables are available at keys with the prefix "vars.". For
|
|
||||||
// example, if looking for the variable "name", it can be accessed as
|
|
||||||
// "vars.name". Implementations that are accessing values need not know that
|
|
||||||
// the underlying context is implemented with gorilla/mux vars.
|
|
||||||
func WithVars(ctx Context, r *http.Request) Context {
|
|
||||||
return &muxVarsContext{
|
|
||||||
Context: ctx,
|
|
||||||
vars: getVarsFromRequest(r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRequestLogger returns a logger that contains fields from the request in
|
|
||||||
// the current context. If the request is not available in the context, no
|
|
||||||
// fields will display. Request loggers can safely be pushed onto the context.
|
|
||||||
func GetRequestLogger(ctx Context) Logger {
|
|
||||||
return GetLogger(ctx,
|
|
||||||
"http.request.id",
|
|
||||||
"http.request.method",
|
|
||||||
"http.request.host",
|
|
||||||
"http.request.uri",
|
|
||||||
"http.request.referer",
|
|
||||||
"http.request.useragent",
|
|
||||||
"http.request.remoteaddr",
|
|
||||||
"http.request.contenttype")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetResponseLogger reads the current response stats and builds a logger.
|
|
||||||
// Because the values are read at call time, pushing a logger returned from
|
|
||||||
// this function on the context will lead to missing or invalid data. Only
|
|
||||||
// call this at the end of a request, after the response has been written.
|
|
||||||
func GetResponseLogger(ctx Context) Logger {
|
|
||||||
l := getLogrusLogger(ctx,
|
|
||||||
"http.response.written",
|
|
||||||
"http.response.status",
|
|
||||||
"http.response.contenttype")
|
|
||||||
|
|
||||||
duration := Since(ctx, "http.request.startedat")
|
|
||||||
|
|
||||||
if duration > 0 {
|
|
||||||
l = l.WithField("http.response.duration", duration.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// httpRequestContext makes information about a request available to context.
|
|
||||||
type httpRequestContext struct {
|
|
||||||
Context
|
|
||||||
|
|
||||||
startedAt time.Time
|
|
||||||
id string
|
|
||||||
r *http.Request
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns a keyed element of the request for use in the context. To get
|
|
||||||
// the request itself, query "request". For other components, access them as
|
|
||||||
// "request.<component>". For example, r.RequestURI
|
|
||||||
func (ctx *httpRequestContext) Value(key interface{}) interface{} {
|
|
||||||
if keyStr, ok := key.(string); ok {
|
|
||||||
if keyStr == "http.request" {
|
|
||||||
return ctx.r
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(keyStr, "http.request.") {
|
|
||||||
goto fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(keyStr, ".")
|
|
||||||
|
|
||||||
if len(parts) != 3 {
|
|
||||||
goto fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
switch parts[2] {
|
|
||||||
case "uri":
|
|
||||||
return ctx.r.RequestURI
|
|
||||||
case "remoteaddr":
|
|
||||||
return RemoteAddr(ctx.r)
|
|
||||||
case "method":
|
|
||||||
return ctx.r.Method
|
|
||||||
case "host":
|
|
||||||
return ctx.r.Host
|
|
||||||
case "referer":
|
|
||||||
referer := ctx.r.Referer()
|
|
||||||
if referer != "" {
|
|
||||||
return referer
|
|
||||||
}
|
|
||||||
case "useragent":
|
|
||||||
return ctx.r.UserAgent()
|
|
||||||
case "id":
|
|
||||||
return ctx.id
|
|
||||||
case "startedat":
|
|
||||||
return ctx.startedAt
|
|
||||||
case "contenttype":
|
|
||||||
ct := ctx.r.Header.Get("Content-Type")
|
|
||||||
if ct != "" {
|
|
||||||
return ct
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fallback:
|
|
||||||
return ctx.Context.Value(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
type muxVarsContext struct {
|
|
||||||
Context
|
|
||||||
vars map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *muxVarsContext) Value(key interface{}) interface{} {
|
|
||||||
if keyStr, ok := key.(string); ok {
|
|
||||||
if keyStr == "vars" {
|
|
||||||
return ctx.vars
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(keyStr, "vars.") {
|
|
||||||
keyStr = strings.TrimPrefix(keyStr, "vars.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if v, ok := ctx.vars[keyStr]; ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.Context.Value(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// instrumentedResponseWriterCN provides response writer information in a
|
|
||||||
// context. It implements http.CloseNotifier so that users can detect
|
|
||||||
// early disconnects.
|
|
||||||
type instrumentedResponseWriterCN struct {
|
|
||||||
instrumentedResponseWriter
|
|
||||||
http.CloseNotifier
|
|
||||||
}
|
|
||||||
|
|
||||||
// instrumentedResponseWriter provides response writer information in a
|
|
||||||
// context. This variant is only used in the case where CloseNotifier is not
|
|
||||||
// implemented by the parent ResponseWriter.
|
|
||||||
type instrumentedResponseWriter struct {
|
|
||||||
http.ResponseWriter
|
|
||||||
Context
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
status int
|
|
||||||
written int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (irw *instrumentedResponseWriter) Write(p []byte) (n int, err error) {
|
|
||||||
n, err = irw.ResponseWriter.Write(p)
|
|
||||||
|
|
||||||
irw.mu.Lock()
|
|
||||||
irw.written += int64(n)
|
|
||||||
|
|
||||||
// Guess the likely status if not set.
|
|
||||||
if irw.status == 0 {
|
|
||||||
irw.status = http.StatusOK
|
|
||||||
}
|
|
||||||
|
|
||||||
irw.mu.Unlock()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (irw *instrumentedResponseWriter) WriteHeader(status int) {
|
|
||||||
irw.ResponseWriter.WriteHeader(status)
|
|
||||||
|
|
||||||
irw.mu.Lock()
|
|
||||||
irw.status = status
|
|
||||||
irw.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (irw *instrumentedResponseWriter) Flush() {
|
|
||||||
if flusher, ok := irw.ResponseWriter.(http.Flusher); ok {
|
|
||||||
flusher.Flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (irw *instrumentedResponseWriter) Value(key interface{}) interface{} {
|
|
||||||
if keyStr, ok := key.(string); ok {
|
|
||||||
if keyStr == "http.response" {
|
|
||||||
return irw
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(keyStr, "http.response.") {
|
|
||||||
goto fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(keyStr, ".")
|
|
||||||
|
|
||||||
if len(parts) != 3 {
|
|
||||||
goto fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
irw.mu.Lock()
|
|
||||||
defer irw.mu.Unlock()
|
|
||||||
|
|
||||||
switch parts[2] {
|
|
||||||
case "written":
|
|
||||||
return irw.written
|
|
||||||
case "status":
|
|
||||||
return irw.status
|
|
||||||
case "contenttype":
|
|
||||||
contentType := irw.Header().Get("Content-Type")
|
|
||||||
if contentType != "" {
|
|
||||||
return contentType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fallback:
|
|
||||||
return irw.Context.Value(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (irw *instrumentedResponseWriterCN) Value(key interface{}) interface{} {
|
|
||||||
if keyStr, ok := key.(string); ok {
|
|
||||||
if keyStr == "http.response" {
|
|
||||||
return irw
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return irw.instrumentedResponseWriter.Value(key)
|
|
||||||
}
|
|
|
@ -1,116 +0,0 @@
|
||||||
package context
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Logger provides a leveled-logging interface.
|
|
||||||
type Logger interface {
|
|
||||||
// standard logger methods
|
|
||||||
Print(args ...interface{})
|
|
||||||
Printf(format string, args ...interface{})
|
|
||||||
Println(args ...interface{})
|
|
||||||
|
|
||||||
Fatal(args ...interface{})
|
|
||||||
Fatalf(format string, args ...interface{})
|
|
||||||
Fatalln(args ...interface{})
|
|
||||||
|
|
||||||
Panic(args ...interface{})
|
|
||||||
Panicf(format string, args ...interface{})
|
|
||||||
Panicln(args ...interface{})
|
|
||||||
|
|
||||||
// Leveled methods, from logrus
|
|
||||||
Debug(args ...interface{})
|
|
||||||
Debugf(format string, args ...interface{})
|
|
||||||
Debugln(args ...interface{})
|
|
||||||
|
|
||||||
Error(args ...interface{})
|
|
||||||
Errorf(format string, args ...interface{})
|
|
||||||
Errorln(args ...interface{})
|
|
||||||
|
|
||||||
Info(args ...interface{})
|
|
||||||
Infof(format string, args ...interface{})
|
|
||||||
Infoln(args ...interface{})
|
|
||||||
|
|
||||||
Warn(args ...interface{})
|
|
||||||
Warnf(format string, args ...interface{})
|
|
||||||
Warnln(args ...interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLogger creates a new context with provided logger.
|
|
||||||
func WithLogger(ctx Context, logger Logger) Context {
|
|
||||||
return WithValue(ctx, "logger", logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLoggerWithField returns a logger instance with the specified field key
|
|
||||||
// and value without affecting the context. Extra specified keys will be
|
|
||||||
// resolved from the context.
|
|
||||||
func GetLoggerWithField(ctx Context, key, value interface{}, keys ...interface{}) Logger {
|
|
||||||
return getLogrusLogger(ctx, keys...).WithField(fmt.Sprint(key), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLoggerWithFields returns a logger instance with the specified fields
|
|
||||||
// without affecting the context. Extra specified keys will be resolved from
|
|
||||||
// the context.
|
|
||||||
func GetLoggerWithFields(ctx Context, fields map[interface{}]interface{}, keys ...interface{}) Logger {
|
|
||||||
// must convert from interface{} -> interface{} to string -> interface{} for logrus.
|
|
||||||
lfields := make(logrus.Fields, len(fields))
|
|
||||||
for key, value := range fields {
|
|
||||||
lfields[fmt.Sprint(key)] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
return getLogrusLogger(ctx, keys...).WithFields(lfields)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLogger returns the logger from the current context, if present. If one
|
|
||||||
// or more keys are provided, they will be resolved on the context and
|
|
||||||
// included in the logger. While context.Value takes an interface, any key
|
|
||||||
// argument passed to GetLogger will be passed to fmt.Sprint when expanded as
|
|
||||||
// a logging key field. If context keys are integer constants, for example,
|
|
||||||
// its recommended that a String method is implemented.
|
|
||||||
func GetLogger(ctx Context, keys ...interface{}) Logger {
|
|
||||||
return getLogrusLogger(ctx, keys...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLogrusLogger returns the logrus logger for the context. If one more keys
|
|
||||||
// are provided, they will be resolved on the context and included in the
|
|
||||||
// logger. Only use this function if specific logrus functionality is
|
|
||||||
// required.
|
|
||||||
func getLogrusLogger(ctx Context, keys ...interface{}) *logrus.Entry {
|
|
||||||
var logger *logrus.Entry
|
|
||||||
|
|
||||||
// Get a logger, if it is present.
|
|
||||||
loggerInterface := ctx.Value("logger")
|
|
||||||
if loggerInterface != nil {
|
|
||||||
if lgr, ok := loggerInterface.(*logrus.Entry); ok {
|
|
||||||
logger = lgr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if logger == nil {
|
|
||||||
fields := logrus.Fields{}
|
|
||||||
|
|
||||||
// Fill in the instance id, if we have it.
|
|
||||||
instanceID := ctx.Value("instance.id")
|
|
||||||
if instanceID != nil {
|
|
||||||
fields["instance.id"] = instanceID
|
|
||||||
}
|
|
||||||
|
|
||||||
fields["go.version"] = runtime.Version()
|
|
||||||
// If no logger is found, just return the standard logger.
|
|
||||||
logger = logrus.StandardLogger().WithFields(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
fields := logrus.Fields{}
|
|
||||||
for _, key := range keys {
|
|
||||||
v := ctx.Value(key)
|
|
||||||
if v != nil {
|
|
||||||
fields[fmt.Sprint(key)] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return logger.WithFields(fields)
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
package context
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/docker/distribution/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WithTrace allocates a traced timing span in a new context. This allows a
|
|
||||||
// caller to track the time between calling WithTrace and the returned done
|
|
||||||
// function. When the done function is called, a log message is emitted with a
|
|
||||||
// "trace.duration" field, corresponding to the elapsed time and a
|
|
||||||
// "trace.func" field, corresponding to the function that called WithTrace.
|
|
||||||
//
|
|
||||||
// The logging keys "trace.id" and "trace.parent.id" are provided to implement
|
|
||||||
// dapper-like tracing. This function should be complemented with a WithSpan
|
|
||||||
// method that could be used for tracing distributed RPC calls.
|
|
||||||
//
|
|
||||||
// The main benefit of this function is to post-process log messages or
|
|
||||||
// intercept them in a hook to provide timing data. Trace ids and parent ids
|
|
||||||
// can also be linked to provide call tracing, if so required.
|
|
||||||
//
|
|
||||||
// Here is an example of the usage:
|
|
||||||
//
|
|
||||||
// func timedOperation(ctx Context) {
|
|
||||||
// ctx, done := WithTrace(ctx)
|
|
||||||
// defer done("this will be the log message")
|
|
||||||
// // ... function body ...
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// If the function ran for roughly 1s, such a usage would emit a log message
|
|
||||||
// as follows:
|
|
||||||
//
|
|
||||||
// INFO[0001] this will be the log message trace.duration=1.004575763s trace.func=github.com/docker/distribution/context.traceOperation trace.id=<id> ...
|
|
||||||
//
|
|
||||||
// Notice that the function name is automatically resolved, along with the
|
|
||||||
// package and a trace id is emitted that can be linked with parent ids.
|
|
||||||
func WithTrace(ctx Context) (Context, func(format string, a ...interface{})) {
|
|
||||||
if ctx == nil {
|
|
||||||
ctx = Background()
|
|
||||||
}
|
|
||||||
|
|
||||||
pc, file, line, _ := runtime.Caller(1)
|
|
||||||
f := runtime.FuncForPC(pc)
|
|
||||||
ctx = &traced{
|
|
||||||
Context: ctx,
|
|
||||||
id: uuid.Generate().String(),
|
|
||||||
start: time.Now(),
|
|
||||||
parent: GetStringValue(ctx, "trace.id"),
|
|
||||||
fnname: f.Name(),
|
|
||||||
file: file,
|
|
||||||
line: line,
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx, func(format string, a ...interface{}) {
|
|
||||||
GetLogger(ctx,
|
|
||||||
"trace.duration",
|
|
||||||
"trace.id",
|
|
||||||
"trace.parent.id",
|
|
||||||
"trace.func",
|
|
||||||
"trace.file",
|
|
||||||
"trace.line").
|
|
||||||
Debugf(format, a...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// traced represents a context that is traced for function call timing. It
|
|
||||||
// also provides fast lookup for the various attributes that are available on
|
|
||||||
// the trace.
|
|
||||||
type traced struct {
|
|
||||||
Context
|
|
||||||
id string
|
|
||||||
parent string
|
|
||||||
start time.Time
|
|
||||||
fnname string
|
|
||||||
file string
|
|
||||||
line int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *traced) Value(key interface{}) interface{} {
|
|
||||||
switch key {
|
|
||||||
case "trace.start":
|
|
||||||
return ts.start
|
|
||||||
case "trace.duration":
|
|
||||||
return time.Since(ts.start)
|
|
||||||
case "trace.id":
|
|
||||||
return ts.id
|
|
||||||
case "trace.parent.id":
|
|
||||||
if ts.parent == "" {
|
|
||||||
return nil // must return nil to signal no parent.
|
|
||||||
}
|
|
||||||
|
|
||||||
return ts.parent
|
|
||||||
case "trace.func":
|
|
||||||
return ts.fnname
|
|
||||||
case "trace.file":
|
|
||||||
return ts.file
|
|
||||||
case "trace.line":
|
|
||||||
return ts.line
|
|
||||||
}
|
|
||||||
|
|
||||||
return ts.Context.Value(key)
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package context
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Since looks up key, which should be a time.Time, and returns the duration
|
|
||||||
// since that time. If the key is not found, the value returned will be zero.
|
|
||||||
// This is helpful when inferring metrics related to context execution times.
|
|
||||||
func Since(ctx Context, key interface{}) time.Duration {
|
|
||||||
if startedAt, ok := ctx.Value(key).(time.Time); ok {
|
|
||||||
return time.Since(startedAt)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStringValue returns a string value from the context. The empty string
|
|
||||||
// will be returned if not found.
|
|
||||||
func GetStringValue(ctx Context, key interface{}) (value string) {
|
|
||||||
if valuev, ok := ctx.Value(key).(string); ok {
|
|
||||||
value = valuev
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package context
|
|
||||||
|
|
||||||
// WithVersion stores the application version in the context. The new context
|
|
||||||
// gets a logger to ensure log messages are marked with the application
|
|
||||||
// version.
|
|
||||||
func WithVersion(ctx Context, version string) Context {
|
|
||||||
ctx = WithValue(ctx, "version", version)
|
|
||||||
// push a new logger onto the stack
|
|
||||||
return WithLogger(ctx, GetLogger(ctx, "version"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetVersion returns the application version from the context. An empty
|
|
||||||
// string may returned if the version was not set on the context.
|
|
||||||
func GetVersion(ctx Context) string {
|
|
||||||
return GetStringValue(ctx, "version")
|
|
||||||
}
|
|
|
@ -1,8 +1,9 @@
|
||||||
package schema2
|
package schema2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package distribution
|
package distribution
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"mime"
|
"mime"
|
||||||
|
|
||||||
"github.com/docker/distribution/context"
|
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
import "github.com/docker/go-metrics"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NamespacePrefix is the namespace of prometheus metrics
|
||||||
|
NamespacePrefix = "registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// StorageNamespace is the prometheus namespace of blob/cache related operations
|
||||||
|
StorageNamespace = metrics.NewNamespace(NamespacePrefix, "storage", nil)
|
||||||
|
)
|
|
@ -1,7 +1,8 @@
|
||||||
package distribution
|
package distribution
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/distribution/context"
|
"context"
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -72,6 +73,21 @@ func (o WithTagOption) Apply(m ManifestService) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithManifestMediaTypes lists the media types the client wishes
|
||||||
|
// the server to provide.
|
||||||
|
func WithManifestMediaTypes(mediaTypes []string) ManifestServiceOption {
|
||||||
|
return WithManifestMediaTypesOption{mediaTypes}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithManifestMediaTypesOption holds a list of accepted media types
|
||||||
|
type WithManifestMediaTypesOption struct{ MediaTypes []string }
|
||||||
|
|
||||||
|
// Apply conforms to the ManifestServiceOption interface
|
||||||
|
func (o WithManifestMediaTypesOption) Apply(m ManifestService) error {
|
||||||
|
// no implementation
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Repository is a named collection of manifests and layers.
|
// Repository is a named collection of manifests and layers.
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
// Named returns the name of the repository.
|
// Named returns the name of the repository.
|
||||||
|
|
|
@ -36,9 +36,5 @@ func ServeJSON(w http.ResponseWriter, err error) error {
|
||||||
|
|
||||||
w.WriteHeader(sc)
|
w.WriteHeader(sc)
|
||||||
|
|
||||||
if err := json.NewEncoder(w).Encode(err); err != nil {
|
return json.NewEncoder(w).Encode(err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,13 +45,13 @@ type Manager interface {
|
||||||
// to a backend.
|
// to a backend.
|
||||||
func NewSimpleManager() Manager {
|
func NewSimpleManager() Manager {
|
||||||
return &simpleManager{
|
return &simpleManager{
|
||||||
Challanges: make(map[string][]Challenge),
|
Challenges: make(map[string][]Challenge),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type simpleManager struct {
|
type simpleManager struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
Challanges map[string][]Challenge
|
Challenges map[string][]Challenge
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeURL(endpoint *url.URL) {
|
func normalizeURL(endpoint *url.URL) {
|
||||||
|
@ -64,7 +64,7 @@ func (m *simpleManager) GetChallenges(endpoint url.URL) ([]Challenge, error) {
|
||||||
|
|
||||||
m.RLock()
|
m.RLock()
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
challenges := m.Challanges[endpoint.String()]
|
challenges := m.Challenges[endpoint.String()]
|
||||||
return challenges, nil
|
return challenges, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ func (m *simpleManager) AddResponse(resp *http.Response) error {
|
||||||
|
|
||||||
m.Lock()
|
m.Lock()
|
||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
m.Challanges[urlCopy.String()] = challenges
|
m.Challenges[urlCopy.String()] = challenges
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/docker/distribution/registry/client"
|
"github.com/docker/distribution/registry/client"
|
||||||
"github.com/docker/distribution/registry/client/auth/challenge"
|
"github.com/docker/distribution/registry/client/auth/challenge"
|
||||||
"github.com/docker/distribution/registry/client/transport"
|
"github.com/docker/distribution/registry/client/transport"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -135,6 +134,8 @@ type tokenHandler struct {
|
||||||
tokenLock sync.Mutex
|
tokenLock sync.Mutex
|
||||||
tokenCache string
|
tokenCache string
|
||||||
tokenExpiration time.Time
|
tokenExpiration time.Time
|
||||||
|
|
||||||
|
logger Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scope is a type which is serializable to a string
|
// Scope is a type which is serializable to a string
|
||||||
|
@ -176,6 +177,18 @@ func (rs RegistryScope) String() string {
|
||||||
return fmt.Sprintf("registry:%s:%s", rs.Name, strings.Join(rs.Actions, ","))
|
return fmt.Sprintf("registry:%s:%s", rs.Name, strings.Join(rs.Actions, ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Logger defines the injectable logging interface, used on TokenHandlers.
|
||||||
|
type Logger interface {
|
||||||
|
Debugf(format string, args ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func logDebugf(logger Logger, format string, args ...interface{}) {
|
||||||
|
if logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Debugf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// TokenHandlerOptions is used to configure a new token handler
|
// TokenHandlerOptions is used to configure a new token handler
|
||||||
type TokenHandlerOptions struct {
|
type TokenHandlerOptions struct {
|
||||||
Transport http.RoundTripper
|
Transport http.RoundTripper
|
||||||
|
@ -185,6 +198,7 @@ type TokenHandlerOptions struct {
|
||||||
ForceOAuth bool
|
ForceOAuth bool
|
||||||
ClientID string
|
ClientID string
|
||||||
Scopes []Scope
|
Scopes []Scope
|
||||||
|
Logger Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// An implementation of clock for providing real time data.
|
// An implementation of clock for providing real time data.
|
||||||
|
@ -220,6 +234,7 @@ func NewTokenHandlerWithOptions(options TokenHandlerOptions) AuthenticationHandl
|
||||||
clientID: options.ClientID,
|
clientID: options.ClientID,
|
||||||
scopes: options.Scopes,
|
scopes: options.Scopes,
|
||||||
clock: realClock{},
|
clock: realClock{},
|
||||||
|
logger: options.Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler
|
return handler
|
||||||
|
@ -264,6 +279,9 @@ func (th *tokenHandler) getToken(params map[string]string, additionalScopes ...s
|
||||||
}
|
}
|
||||||
var addedScopes bool
|
var addedScopes bool
|
||||||
for _, scope := range additionalScopes {
|
for _, scope := range additionalScopes {
|
||||||
|
if hasScope(scopes, scope) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
scopes = append(scopes, scope)
|
scopes = append(scopes, scope)
|
||||||
addedScopes = true
|
addedScopes = true
|
||||||
}
|
}
|
||||||
|
@ -287,6 +305,15 @@ func (th *tokenHandler) getToken(params map[string]string, additionalScopes ...s
|
||||||
return th.tokenCache, nil
|
return th.tokenCache, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasScope(scopes []string, scope string) bool {
|
||||||
|
for _, s := range scopes {
|
||||||
|
if s == scope {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type postTokenResponse struct {
|
type postTokenResponse struct {
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
@ -348,7 +375,7 @@ func (th *tokenHandler) fetchTokenWithOAuth(realm *url.URL, refreshToken, servic
|
||||||
if tr.ExpiresIn < minimumTokenLifetimeSeconds {
|
if tr.ExpiresIn < minimumTokenLifetimeSeconds {
|
||||||
// The default/minimum lifetime.
|
// The default/minimum lifetime.
|
||||||
tr.ExpiresIn = minimumTokenLifetimeSeconds
|
tr.ExpiresIn = minimumTokenLifetimeSeconds
|
||||||
logrus.Debugf("Increasing token expiration to: %d seconds", tr.ExpiresIn)
|
logDebugf(th.logger, "Increasing token expiration to: %d seconds", tr.ExpiresIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tr.IssuedAt.IsZero() {
|
if tr.IssuedAt.IsZero() {
|
||||||
|
@ -439,7 +466,7 @@ func (th *tokenHandler) fetchTokenWithBasicAuth(realm *url.URL, service string,
|
||||||
if tr.ExpiresIn < minimumTokenLifetimeSeconds {
|
if tr.ExpiresIn < minimumTokenLifetimeSeconds {
|
||||||
// The default/minimum lifetime.
|
// The default/minimum lifetime.
|
||||||
tr.ExpiresIn = minimumTokenLifetimeSeconds
|
tr.ExpiresIn = minimumTokenLifetimeSeconds
|
||||||
logrus.Debugf("Increasing token expiration to: %d seconds", tr.ExpiresIn)
|
logDebugf(th.logger, "Increasing token expiration to: %d seconds", tr.ExpiresIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tr.IssuedAt.IsZero() {
|
if tr.IssuedAt.IsZero() {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -9,7 +10,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type httpBlobUpload struct {
|
type httpBlobUpload struct {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -14,7 +15,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/api/v2"
|
"github.com/docker/distribution/registry/api/v2"
|
||||||
"github.com/docker/distribution/registry/client/transport"
|
"github.com/docker/distribution/registry/client/transport"
|
||||||
|
@ -62,7 +62,7 @@ func checkHTTPRedirect(req *http.Request, via []*http.Request) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRegistry creates a registry namespace which can be used to get a listing of repositories
|
// NewRegistry creates a registry namespace which can be used to get a listing of repositories
|
||||||
func NewRegistry(ctx context.Context, baseURL string, transport http.RoundTripper) (Registry, error) {
|
func NewRegistry(baseURL string, transport http.RoundTripper) (Registry, error) {
|
||||||
ub, err := v2.NewURLBuilderFromString(baseURL, false)
|
ub, err := v2.NewURLBuilderFromString(baseURL, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -75,9 +75,8 @@ func NewRegistry(ctx context.Context, baseURL string, transport http.RoundTrippe
|
||||||
}
|
}
|
||||||
|
|
||||||
return ®istry{
|
return ®istry{
|
||||||
client: client,
|
client: client,
|
||||||
ub: ub,
|
ub: ub,
|
||||||
context: ctx,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +132,7 @@ func (r *registry) Repositories(ctx context.Context, entries []string, last stri
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRepository creates a new Repository for the given repository name and base URL.
|
// NewRepository creates a new Repository for the given repository name and base URL.
|
||||||
func NewRepository(ctx context.Context, name reference.Named, baseURL string, transport http.RoundTripper) (distribution.Repository, error) {
|
func NewRepository(name reference.Named, baseURL string, transport http.RoundTripper) (distribution.Repository, error) {
|
||||||
ub, err := v2.NewURLBuilderFromString(baseURL, false)
|
ub, err := v2.NewURLBuilderFromString(baseURL, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -146,10 +145,9 @@ func NewRepository(ctx context.Context, name reference.Named, baseURL string, tr
|
||||||
}
|
}
|
||||||
|
|
||||||
return &repository{
|
return &repository{
|
||||||
client: client,
|
client: client,
|
||||||
ub: ub,
|
ub: ub,
|
||||||
name: name,
|
name: name,
|
||||||
context: ctx,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,32 +188,35 @@ func (r *repository) Manifests(ctx context.Context, options ...distribution.Mani
|
||||||
|
|
||||||
func (r *repository) Tags(ctx context.Context) distribution.TagService {
|
func (r *repository) Tags(ctx context.Context) distribution.TagService {
|
||||||
return &tags{
|
return &tags{
|
||||||
client: r.client,
|
client: r.client,
|
||||||
ub: r.ub,
|
ub: r.ub,
|
||||||
context: r.context,
|
name: r.Named(),
|
||||||
name: r.Named(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// tags implements remote tagging operations.
|
// tags implements remote tagging operations.
|
||||||
type tags struct {
|
type tags struct {
|
||||||
client *http.Client
|
client *http.Client
|
||||||
ub *v2.URLBuilder
|
ub *v2.URLBuilder
|
||||||
context context.Context
|
name reference.Named
|
||||||
name reference.Named
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All returns all tags
|
// All returns all tags
|
||||||
func (t *tags) All(ctx context.Context) ([]string, error) {
|
func (t *tags) All(ctx context.Context) ([]string, error) {
|
||||||
var tags []string
|
var tags []string
|
||||||
|
|
||||||
u, err := t.ub.BuildTagsURL(t.name)
|
listURLStr, err := t.ub.BuildTagsURL(t.name)
|
||||||
|
if err != nil {
|
||||||
|
return tags, err
|
||||||
|
}
|
||||||
|
|
||||||
|
listURL, err := url.Parse(listURLStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tags, err
|
return tags, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
resp, err := t.client.Get(u)
|
resp, err := t.client.Get(listURL.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tags, err
|
return tags, err
|
||||||
}
|
}
|
||||||
|
@ -235,7 +236,13 @@ func (t *tags) All(ctx context.Context) ([]string, error) {
|
||||||
}
|
}
|
||||||
tags = append(tags, tagsResponse.Tags...)
|
tags = append(tags, tagsResponse.Tags...)
|
||||||
if link := resp.Header.Get("Link"); link != "" {
|
if link := resp.Header.Get("Link"); link != "" {
|
||||||
u = strings.Trim(strings.Split(link, ";")[0], "<>")
|
linkURLStr := strings.Trim(strings.Split(link, ";")[0], "<>")
|
||||||
|
linkURL, err := url.Parse(linkURLStr)
|
||||||
|
if err != nil {
|
||||||
|
return tags, err
|
||||||
|
}
|
||||||
|
|
||||||
|
listURL = listURL.ResolveReference(linkURL)
|
||||||
} else {
|
} else {
|
||||||
return tags, nil
|
return tags, nil
|
||||||
}
|
}
|
||||||
|
@ -321,7 +328,8 @@ func (t *tags) Get(ctx context.Context, tag string) (distribution.Descriptor, er
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case resp.StatusCode >= 200 && resp.StatusCode < 400:
|
case resp.StatusCode >= 200 && resp.StatusCode < 400 && len(resp.Header.Get("Docker-Content-Digest")) > 0:
|
||||||
|
// if the response is a success AND a Docker-Content-Digest can be retrieved from the headers
|
||||||
return descriptorFromResponse(resp)
|
return descriptorFromResponse(resp)
|
||||||
default:
|
default:
|
||||||
// if the response is an error - there will be no body to decode.
|
// if the response is an error - there will be no body to decode.
|
||||||
|
@ -421,18 +429,22 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
|
||||||
ref reference.Named
|
ref reference.Named
|
||||||
err error
|
err error
|
||||||
contentDgst *digest.Digest
|
contentDgst *digest.Digest
|
||||||
|
mediaTypes []string
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
if opt, ok := option.(distribution.WithTagOption); ok {
|
switch opt := option.(type) {
|
||||||
|
case distribution.WithTagOption:
|
||||||
digestOrTag = opt.Tag
|
digestOrTag = opt.Tag
|
||||||
ref, err = reference.WithTag(ms.name, opt.Tag)
|
ref, err = reference.WithTag(ms.name, opt.Tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else if opt, ok := option.(contentDigestOption); ok {
|
case contentDigestOption:
|
||||||
contentDgst = opt.digest
|
contentDgst = opt.digest
|
||||||
} else {
|
case distribution.WithManifestMediaTypesOption:
|
||||||
|
mediaTypes = opt.MediaTypes
|
||||||
|
default:
|
||||||
err := option.Apply(ms)
|
err := option.Apply(ms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -448,6 +460,10 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(mediaTypes) == 0 {
|
||||||
|
mediaTypes = distribution.ManifestMediaTypes()
|
||||||
|
}
|
||||||
|
|
||||||
u, err := ms.ub.BuildManifestURL(ref)
|
u, err := ms.ub.BuildManifestURL(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -458,7 +474,7 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range distribution.ManifestMediaTypes() {
|
for _, t := range mediaTypes {
|
||||||
req.Header.Add("Accept", t)
|
req.Header.Add("Accept", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/distribution/context"
|
"context"
|
||||||
"github.com/opencontainers/go-digest"
|
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
|
prometheus "github.com/docker/distribution/metrics"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Metrics is used to hold metric counters
|
// Metrics is used to hold metric counters
|
||||||
|
@ -16,12 +17,20 @@ type Metrics struct {
|
||||||
Misses uint64
|
Misses uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Logger can be provided on the MetricsTracker to log errors.
|
||||||
|
//
|
||||||
|
// Usually, this is just a proxy to dcontext.GetLogger.
|
||||||
|
type Logger interface {
|
||||||
|
Errorf(format string, args ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
// MetricsTracker represents a metric tracker
|
// MetricsTracker represents a metric tracker
|
||||||
// which simply counts the number of hits and misses.
|
// which simply counts the number of hits and misses.
|
||||||
type MetricsTracker interface {
|
type MetricsTracker interface {
|
||||||
Hit()
|
Hit()
|
||||||
Miss()
|
Miss()
|
||||||
Metrics() Metrics
|
Metrics() Metrics
|
||||||
|
Logger(context.Context) Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type cachedBlobStatter struct {
|
type cachedBlobStatter struct {
|
||||||
|
@ -30,6 +39,11 @@ type cachedBlobStatter struct {
|
||||||
tracker MetricsTracker
|
tracker MetricsTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// cacheCount is the number of total cache request received/hits/misses
|
||||||
|
cacheCount = prometheus.StorageNamespace.NewLabeledCounter("cache", "The number of cache request received", "type")
|
||||||
|
)
|
||||||
|
|
||||||
// NewCachedBlobStatter creates a new statter which prefers a cache and
|
// NewCachedBlobStatter creates a new statter which prefers a cache and
|
||||||
// falls back to a backend.
|
// falls back to a backend.
|
||||||
func NewCachedBlobStatter(cache distribution.BlobDescriptorService, backend distribution.BlobDescriptorService) distribution.BlobDescriptorService {
|
func NewCachedBlobStatter(cache distribution.BlobDescriptorService, backend distribution.BlobDescriptorService) distribution.BlobDescriptorService {
|
||||||
|
@ -50,20 +64,22 @@ func NewCachedBlobStatterWithMetrics(cache distribution.BlobDescriptorService, b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cbds *cachedBlobStatter) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
|
func (cbds *cachedBlobStatter) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
|
||||||
|
cacheCount.WithValues("Request").Inc(1)
|
||||||
desc, err := cbds.cache.Stat(ctx, dgst)
|
desc, err := cbds.cache.Stat(ctx, dgst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != distribution.ErrBlobUnknown {
|
if err != distribution.ErrBlobUnknown {
|
||||||
context.GetLogger(ctx).Errorf("error retrieving descriptor from cache: %v", err)
|
logErrorf(ctx, cbds.tracker, "error retrieving descriptor from cache: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
goto fallback
|
goto fallback
|
||||||
}
|
}
|
||||||
|
cacheCount.WithValues("Hit").Inc(1)
|
||||||
if cbds.tracker != nil {
|
if cbds.tracker != nil {
|
||||||
cbds.tracker.Hit()
|
cbds.tracker.Hit()
|
||||||
}
|
}
|
||||||
return desc, nil
|
return desc, nil
|
||||||
fallback:
|
fallback:
|
||||||
|
cacheCount.WithValues("Miss").Inc(1)
|
||||||
if cbds.tracker != nil {
|
if cbds.tracker != nil {
|
||||||
cbds.tracker.Miss()
|
cbds.tracker.Miss()
|
||||||
}
|
}
|
||||||
|
@ -73,7 +89,7 @@ fallback:
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cbds.cache.SetDescriptor(ctx, dgst, desc); err != nil {
|
if err := cbds.cache.SetDescriptor(ctx, dgst, desc); err != nil {
|
||||||
context.GetLogger(ctx).Errorf("error adding descriptor %v to cache: %v", desc.Digest, err)
|
logErrorf(ctx, cbds.tracker, "error adding descriptor %v to cache: %v", desc.Digest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return desc, err
|
return desc, err
|
||||||
|
@ -95,7 +111,19 @@ func (cbds *cachedBlobStatter) Clear(ctx context.Context, dgst digest.Digest) er
|
||||||
|
|
||||||
func (cbds *cachedBlobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
|
func (cbds *cachedBlobStatter) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
|
||||||
if err := cbds.cache.SetDescriptor(ctx, dgst, desc); err != nil {
|
if err := cbds.cache.SetDescriptor(ctx, dgst, desc); err != nil {
|
||||||
context.GetLogger(ctx).Errorf("error adding descriptor %v to cache: %v", desc.Digest, err)
|
logErrorf(ctx, cbds.tracker, "error adding descriptor %v to cache: %v", desc.Digest, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logErrorf(ctx context.Context, tracker MetricsTracker, format string, args ...interface{}) {
|
||||||
|
if tracker == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := tracker.Logger(ctx)
|
||||||
|
if logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Errorf(format, args...)
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package memory
|
package memory
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/distribution"
|
"github.com/docker/distribution"
|
||||||
"github.com/docker/distribution/context"
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/storage/cache"
|
"github.com/docker/distribution/registry/storage/cache"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package distribution
|
package distribution
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/docker/distribution/context"
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TagService provides access to information about tagged objects.
|
// TagService provides access to information about tagged objects.
|
||||||
|
|
|
@ -1,26 +1,32 @@
|
||||||
github.com/Azure/azure-sdk-for-go 088007b3b08cc02b27f2eadfdcd870958460ce7e
|
github.com/Azure/azure-sdk-for-go 088007b3b08cc02b27f2eadfdcd870958460ce7e
|
||||||
github.com/Azure/go-autorest ec5f4903f77ed9927ac95b19ab8e44ada64c1356
|
github.com/Azure/go-autorest ec5f4903f77ed9927ac95b19ab8e44ada64c1356
|
||||||
github.com/sirupsen/logrus 3d4380f53a34dcdc95f0c1db702615992b38d9a4
|
github.com/sirupsen/logrus 3d4380f53a34dcdc95f0c1db702615992b38d9a4
|
||||||
github.com/aws/aws-sdk-go c6fc52983ea2375810aa38ddb5370e9cdf611716
|
github.com/aws/aws-sdk-go 5bcc0a238d880469f949fc7cd24e35f32ab80cbd
|
||||||
github.com/bshuster-repo/logrus-logstash-hook d2c0ecc1836d91814e15e23bb5dc309c3ef51f4a
|
github.com/bshuster-repo/logrus-logstash-hook d2c0ecc1836d91814e15e23bb5dc309c3ef51f4a
|
||||||
|
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||||
github.com/bugsnag/bugsnag-go b1d153021fcd90ca3f080db36bec96dc690fb274
|
github.com/bugsnag/bugsnag-go b1d153021fcd90ca3f080db36bec96dc690fb274
|
||||||
github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702
|
github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702
|
||||||
github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782
|
github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782
|
||||||
github.com/denverdino/aliyungo afedced274aa9a7fcdd47ac97018f0f8db4e5de2
|
github.com/denverdino/aliyungo afedced274aa9a7fcdd47ac97018f0f8db4e5de2
|
||||||
github.com/dgrijalva/jwt-go a601269ab70c205d26370c16f7c81e9017c14e04
|
github.com/dgrijalva/jwt-go a601269ab70c205d26370c16f7c81e9017c14e04
|
||||||
|
github.com/docker/go-metrics 399ea8c73916000c64c2c76e8da00ca82f8387ab
|
||||||
github.com/docker/goamz f0a21f5b2e12f83a505ecf79b633bb2035cf6f85
|
github.com/docker/goamz f0a21f5b2e12f83a505ecf79b633bb2035cf6f85
|
||||||
github.com/docker/libtrust fa567046d9b14f6aa788882a950d69651d230b21
|
github.com/docker/libtrust fa567046d9b14f6aa788882a950d69651d230b21
|
||||||
github.com/garyburd/redigo 535138d7bcd717d6531c701ef5933d98b1866257
|
github.com/garyburd/redigo 535138d7bcd717d6531c701ef5933d98b1866257
|
||||||
github.com/go-ini/ini 2ba15ac2dc9cdf88c110ec2dc0ced7fa45f5678c
|
github.com/go-ini/ini 2ba15ac2dc9cdf88c110ec2dc0ced7fa45f5678c
|
||||||
github.com/golang/protobuf 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3
|
github.com/golang/protobuf 8d92cf5fc15a4382f8964b08e1f42a75c0591aa3
|
||||||
github.com/gorilla/context 14f550f51af52180c2eefed15e5fd18d63c0a64a
|
|
||||||
github.com/gorilla/handlers 60c7bfde3e33c201519a200a4507a158cc03a17b
|
github.com/gorilla/handlers 60c7bfde3e33c201519a200a4507a158cc03a17b
|
||||||
github.com/gorilla/mux 599cba5e7b6137d46ddf58fb1765f5d928e69604
|
github.com/gorilla/mux 599cba5e7b6137d46ddf58fb1765f5d928e69604
|
||||||
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||||
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
||||||
|
github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c
|
||||||
github.com/miekg/dns 271c58e0c14f552178ea321a545ff9af38930f39
|
github.com/miekg/dns 271c58e0c14f552178ea321a545ff9af38930f39
|
||||||
github.com/mitchellh/mapstructure 482a9fd5fa83e8c4e7817413b80f3eb8feec03ef
|
github.com/mitchellh/mapstructure 482a9fd5fa83e8c4e7817413b80f3eb8feec03ef
|
||||||
github.com/ncw/swift b964f2ca856aac39885e258ad25aec08d5f64ee6
|
github.com/ncw/swift b964f2ca856aac39885e258ad25aec08d5f64ee6
|
||||||
|
github.com/prometheus/client_golang c332b6f63c0658a65eca15c0e5247ded801cf564
|
||||||
|
github.com/prometheus/client_model 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c
|
||||||
|
github.com/prometheus/common 89604d197083d4781071d3c65855d24ecfb0a563
|
||||||
|
github.com/prometheus/procfs cb4147076ac75738c9a7d279075a253c0cc5acbd
|
||||||
github.com/spf13/cobra 312092086bed4968099259622145a0c9ae280064
|
github.com/spf13/cobra 312092086bed4968099259622145a0c9ae280064
|
||||||
github.com/spf13/pflag 5644820622454e71517561946e3d94b9f9db6842
|
github.com/spf13/pflag 5644820622454e71517561946e3d94b9f9db6842
|
||||||
github.com/stevvooe/resumable 2aaf90b2ceea5072cb503ef2a620b08ff3119870
|
github.com/stevvooe/resumable 2aaf90b2ceea5072cb503ef2a620b08ff3119870
|
||||||
|
|
|
@ -7,7 +7,7 @@ package types
|
||||||
// swagger:model Port
|
// swagger:model Port
|
||||||
type Port struct {
|
type Port struct {
|
||||||
|
|
||||||
// IP
|
// Host IP address that the container's port is mapped to
|
||||||
IP string `json:"IP,omitempty"`
|
IP string `json:"IP,omitempty"`
|
||||||
|
|
||||||
// Port on the container
|
// Port on the container
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package volume // import "github.com/docker/docker/api/types/volume"
|
package volume
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// 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
|
// See hack/generate-swagger-api.sh
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// VolumesCreateBody volumes create body
|
// VolumeCreateBody
|
||||||
// swagger:model VolumesCreateBody
|
// swagger:model VolumeCreateBody
|
||||||
type VolumesCreateBody struct {
|
type VolumeCreateBody struct {
|
||||||
|
|
||||||
// Name of the volume driver to use.
|
// Name of the volume driver to use.
|
||||||
// Required: true
|
// Required: true
|
|
@ -1,4 +1,4 @@
|
||||||
package volume // import "github.com/docker/docker/api/types/volume"
|
package volume
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// DO NOT EDIT THIS FILE
|
// 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"
|
import "github.com/docker/docker/api/types"
|
||||||
|
|
||||||
// VolumesListOKBody volumes list o k body
|
// VolumeListOKBody
|
||||||
// swagger:model VolumesListOKBody
|
// swagger:model VolumeListOKBody
|
||||||
type VolumesListOKBody struct {
|
type VolumeListOKBody struct {
|
||||||
|
|
||||||
// List of volumes
|
// List of volumes
|
||||||
// Required: true
|
// Required: true
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BuildCachePrune requests the daemon to delete unused cache data
|
// BuildCachePrune requests the daemon to delete unused cache data
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckpointCreate creates a checkpoint from the given container with the given name
|
// CheckpointCreate creates a checkpoint from the given container with the given name
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckpointDelete deletes the checkpoint with the given name from the given container
|
// CheckpointDelete deletes the checkpoint with the given name from the given container
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckpointList returns the checkpoints of the given container in the docker host
|
// CheckpointList returns the checkpoints of the given container in the docker host
|
||||||
|
|
|
@ -42,6 +42,7 @@ For example, to list running containers (the equivalent of "docker ps"):
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -57,7 +58,6 @@ import (
|
||||||
"github.com/docker/go-connections/sockets"
|
"github.com/docker/go-connections/sockets"
|
||||||
"github.com/docker/go-connections/tlsconfig"
|
"github.com/docker/go-connections/tlsconfig"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrRedirect is the error returned by checkRedirect when the request is non-GET.
|
// ErrRedirect is the error returned by checkRedirect when the request is non-GET.
|
||||||
|
@ -356,6 +356,11 @@ func (cli *Client) DaemonHost() string {
|
||||||
return cli.host
|
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
|
// ParseHostURL parses a url string, validates the string is a host url, and
|
||||||
// returns the parsed URL
|
// returns the parsed URL
|
||||||
func ParseHostURL(host string) (*url.URL, error) {
|
func ParseHostURL(host string) (*url.URL, error) {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConfigCreate creates a new Config.
|
// ConfigCreate creates a new Config.
|
||||||
|
|
|
@ -2,11 +2,11 @@ package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConfigInspectWithRaw returns the config information with raw data
|
// ConfigInspectWithRaw returns the config information with raw data
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConfigList returns the list of configs.
|
// ConfigList returns the list of configs.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import "golang.org/x/net/context"
|
import "context"
|
||||||
|
|
||||||
// ConfigRemove removes a Config.
|
// ConfigRemove removes a Config.
|
||||||
func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
|
func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConfigUpdate attempts to update a Config
|
// ConfigUpdate attempts to update a Config
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerAttach attaches a connection to a container in the server.
|
// ContainerAttach attaches a connection to a container in the server.
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerCommit applies changes into a container and creates a new tagged image.
|
// ContainerCommit applies changes into a container and creates a new tagged image.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -10,8 +11,6 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -8,7 +9,6 @@ import (
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type configWrapper struct {
|
type configWrapper struct {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerDiff shows differences in a container filesystem since it was started.
|
// ContainerDiff shows differences in a container filesystem since it was started.
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerExecCreate creates a new exec configuration to run an exec process.
|
// ContainerExecCreate creates a new exec configuration to run an exec process.
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerExport retrieves the raw contents of a container
|
// ContainerExport retrieves the raw contents of a container
|
||||||
|
|
|
@ -2,12 +2,12 @@ package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerInspect returns the container information.
|
// ContainerInspect returns the container information.
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerKill terminates the container process but does not remove the container from the docker host.
|
// ContainerKill terminates the container process but does not remove the container from the docker host.
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerList returns the list of containers in the docker host.
|
// ContainerList returns the list of containers in the docker host.
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
timetypes "github.com/docker/docker/api/types/time"
|
timetypes "github.com/docker/docker/api/types/time"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import "golang.org/x/net/context"
|
import "context"
|
||||||
|
|
||||||
// ContainerPause pauses the main process of a given container without terminating it.
|
// ContainerPause pauses the main process of a given container without terminating it.
|
||||||
func (cli *Client) ContainerPause(ctx context.Context, containerID string) error {
|
func (cli *Client) ContainerPause(ctx context.Context, containerID string) error {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainersPrune requests the daemon to delete unused data
|
// ContainersPrune requests the daemon to delete unused data
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerRemove kills and removes a container from the docker host.
|
// ContainerRemove kills and removes a container from the docker host.
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerRename changes the name of a given container.
|
// ContainerRename changes the name of a given container.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerResize changes the size of the tty for a container.
|
// ContainerResize changes the size of the tty for a container.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
timetypes "github.com/docker/docker/api/types/time"
|
timetypes "github.com/docker/docker/api/types/time"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerRestart stops and starts a container again.
|
// ContainerRestart stops and starts a container again.
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerStats returns near realtime stats for a given container.
|
// ContainerStats returns near realtime stats for a given container.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
timetypes "github.com/docker/docker/api/types/time"
|
timetypes "github.com/docker/docker/api/types/time"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerStop stops a container without terminating the process.
|
// ContainerStop stops a container without terminating the process.
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerTop shows process information from within a container.
|
// ContainerTop shows process information from within a container.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import "golang.org/x/net/context"
|
import "context"
|
||||||
|
|
||||||
// ContainerUnpause resumes the process execution within a container
|
// ContainerUnpause resumes the process execution within a container
|
||||||
func (cli *Client) ContainerUnpause(ctx context.Context, containerID string) error {
|
func (cli *Client) ContainerUnpause(ctx context.Context, containerID string) error {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerUpdate updates resources of a container
|
// ContainerUpdate updates resources of a container
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DiskUsage requests the current data usage from the daemon
|
// DiskUsage requests the current data usage from the daemon
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DistributionInspect returns the image digest with full Manifest
|
// DistributionInspect returns the image digest with full Manifest
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/events"
|
"github.com/docker/docker/api/types/events"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
|
|
@ -2,6 +2,7 @@ package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
@ -14,7 +15,6 @@ import (
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/go-connections/sockets"
|
"github.com/docker/go-connections/sockets"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// tlsClientCon holds tls information and a dialed connection.
|
// tlsClientCon holds tls information and a dialed connection.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
@ -9,8 +10,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageHistory returns the changes in an image in history format.
|
// ImageHistory returns the changes in an image in history format.
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,11 +2,11 @@ package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageInspectWithRaw returns the image information and its raw representation.
|
// ImageInspectWithRaw returns the image information and its raw representation.
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageList returns a list of images in the docker host.
|
// ImageList returns a list of images in the docker host.
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImagesPrune requests the daemon to delete unused data
|
// ImagesPrune requests the daemon to delete unused data
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageRemove removes an image from the docker host.
|
// ImageRemove removes an image from the docker host.
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageSave retrieves one or more images from the docker host as an io.ReadCloser.
|
// ImageSave retrieves one or more images from the docker host as an io.ReadCloser.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -9,7 +10,6 @@ import (
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageSearch makes the docker host to search by a term in a remote registry.
|
// ImageSearch makes the docker host to search by a term in a remote registry.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImageTag tags an image in the docker host
|
// ImageTag tags an image in the docker host
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Info returns information about the docker server.
|
// Info returns information about the docker server.
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
@ -14,7 +16,6 @@ import (
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
volumetypes "github.com/docker/docker/api/types/volume"
|
volumetypes "github.com/docker/docker/api/types/volume"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommonAPIClient is the common methods between stable and experimental versions of APIClient.
|
// CommonAPIClient is the common methods between stable and experimental versions of APIClient.
|
||||||
|
@ -33,6 +34,7 @@ type CommonAPIClient interface {
|
||||||
VolumeAPIClient
|
VolumeAPIClient
|
||||||
ClientVersion() string
|
ClientVersion() string
|
||||||
DaemonHost() string
|
DaemonHost() string
|
||||||
|
HTTPClient() *http.Client
|
||||||
ServerVersion(ctx context.Context) (types.Version, error)
|
ServerVersion(ctx context.Context) (types.Version, error)
|
||||||
NegotiateAPIVersion(ctx context.Context)
|
NegotiateAPIVersion(ctx context.Context)
|
||||||
NegotiateAPIVersionPing(types.Ping)
|
NegotiateAPIVersionPing(types.Ping)
|
||||||
|
@ -168,10 +170,10 @@ type SystemAPIClient interface {
|
||||||
|
|
||||||
// VolumeAPIClient defines API client methods for the volumes
|
// VolumeAPIClient defines API client methods for the volumes
|
||||||
type VolumeAPIClient interface {
|
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)
|
VolumeInspect(ctx context.Context, volumeID string) (types.Volume, error)
|
||||||
VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, 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
|
VolumeRemove(ctx context.Context, volumeID string, force bool) error
|
||||||
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (types.VolumesPruneReport, error)
|
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (types.VolumesPruneReport, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type apiClientExperimental interface {
|
type apiClientExperimental interface {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegistryLogin authenticates the docker server with a given docker registry.
|
// RegistryLogin authenticates the docker server with a given docker registry.
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetworkConnect connects a container to an existent network in the docker host.
|
// NetworkConnect connects a container to an existent network in the docker host.
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetworkCreate creates a new network in the docker host.
|
// NetworkCreate creates a new network in the docker host.
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetworkDisconnect disconnects a container from an existent network in the docker host.
|
// NetworkDisconnect disconnects a container from an existent network in the docker host.
|
||||||
|
|
|
@ -2,12 +2,12 @@ package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetworkInspect returns the information for a specific network configured in the docker host.
|
// NetworkInspect returns the information for a specific network configured in the docker host.
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetworkList returns the list of networks configured in the docker host.
|
// NetworkList returns the list of networks configured in the docker host.
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetworksPrune requests the daemon to delete unused networks
|
// NetworksPrune requests the daemon to delete unused networks
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import "golang.org/x/net/context"
|
import "context"
|
||||||
|
|
||||||
// NetworkRemove removes an existent network from the docker host.
|
// NetworkRemove removes an existent network from the docker host.
|
||||||
func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error {
|
func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error {
|
||||||
|
|
|
@ -2,11 +2,11 @@ package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeInspectWithRaw returns the node information.
|
// NodeInspectWithRaw returns the node information.
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package client // import "github.com/docker/docker/client"
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeList returns the list of nodes.
|
// NodeList returns the list of nodes.
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue