Browse code

Merge pull request #27774 from runcom/vendor-distr

vendor docker/distribution fbb70dc3a14ca65cdac3aaf5e5122b03b42f6fbc

Tibor Vass authored on 2016/10/28 09:07:03
Showing 14 changed files
... ...
@@ -91,7 +91,7 @@ clone git github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
91 91
 clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
92 92
 
93 93
 # get graph and distribution packages
94
-clone git github.com/docker/distribution 77b9d2997abcded79a5314970fe69a44c93c25fb
94
+clone git github.com/docker/distribution fbb70dc3a14ca65cdac3aaf5e5122b03b42f6fbc
95 95
 clone git github.com/vbatts/tar-split v0.10.1
96 96
 
97 97
 # get go-zfs packages
... ...
@@ -11,7 +11,7 @@ Most people should use the [official Registry docker image](https://hub.docker.c
11 11
 
12 12
 People looking for advanced operational use cases might consider rolling their own image with a custom Dockerfile inheriting `FROM registry:2`.
13 13
 
14
-OS X users who want to run natively can do so following [the instructions here](osx-setup-guide.md).
14
+OS X users who want to run natively can do so following [the instructions here](https://github.com/docker/docker.github.io/blob/master/registry/recipes/osx-setup-guide.md).
15 15
 
16 16
 ### Gotchas
17 17
 
18 18
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// Only run on Linux atm
1
+wrappedNode(label: 'docker') {
2
+  deleteDir()
3
+  stage "checkout"
4
+  checkout scm
5
+
6
+  documentationChecker("docs")
7
+}
... ...
@@ -27,22 +27,25 @@ version/version.go:
27 27
 # Required for go 1.5 to build
28 28
 GO15VENDOREXPERIMENT := 1
29 29
 
30
+# Go files
31
+GOFILES=$(shell find . -type f -name '*.go')
32
+
30 33
 # Package list
31
-PKGS := $(shell go list -tags "${DOCKER_BUILDTAGS}" ./... | grep -v ^github.com/docker/distribution/vendor/)
34
+PKGS=$(shell go list -tags "${DOCKER_BUILDTAGS}" ./... | grep -v ^github.com/docker/distribution/vendor/)
32 35
 
33 36
 # Resolving binary dependencies for specific targets
34
-GOLINT := $(shell which golint || echo '')
35
-GODEP := $(shell which godep || echo '')
37
+GOLINT=$(shell which golint || echo '')
38
+GODEP=$(shell which godep || echo '')
36 39
 
37
-${PREFIX}/bin/registry: $(wildcard **/*.go)
40
+${PREFIX}/bin/registry: $(GOFILES)
38 41
 	@echo "+ $@"
39 42
 	@go build -tags "${DOCKER_BUILDTAGS}" -o $@ ${GO_LDFLAGS}  ${GO_GCFLAGS} ./cmd/registry
40 43
 
41
-${PREFIX}/bin/digest:  $(wildcard **/*.go)
44
+${PREFIX}/bin/digest:  $(GOFILES)
42 45
 	@echo "+ $@"
43 46
 	@go build -tags "${DOCKER_BUILDTAGS}" -o $@ ${GO_LDFLAGS}  ${GO_GCFLAGS} ./cmd/digest
44 47
 
45
-${PREFIX}/bin/registry-api-descriptor-template: $(wildcard **/*.go)
48
+${PREFIX}/bin/registry-api-descriptor-template: $(GOFILES)
46 49
 	@echo "+ $@"
47 50
 	@go build -o $@ ${GO_LDFLAGS} ${GO_GCFLAGS} ./cmd/registry-api-descriptor-template
48 51
 
... ...
@@ -19,7 +19,7 @@ This repository contains the following components:
19 19
 | **registry**       | An implementation of the [Docker Registry HTTP API V2](docs/spec/api.md) for use with docker 1.6+.                                                                                                  |
20 20
 | **libraries**      | A rich set of libraries for interacting with distribution components. Please see [godoc](https://godoc.org/github.com/docker/distribution) for details. **Note**: These libraries are **unstable**. |
21 21
 | **specifications** | _Distribution_ related specifications are available in [docs/spec](docs/spec)                                                                                                                        |
22
-| **documentation**  | Docker's full documentation set is available at [docs.docker.com](https://docs.docker.com). This repository [contains the subset](docs/index.md) related just to the registry.                                                                                                                                          |
22
+| **documentation**  | Docker's full documentation set is available at [docs.docker.com](https://docs.docker.com). This repository [contains the subset](docs/) related just to the registry.                                                                                                                                          |
23 23
 
24 24
 ### How does this integrate with Docker engine?
25 25
 
... ...
@@ -60,15 +60,15 @@ For information on upcoming functionality, please see [ROADMAP.md](ROADMAP.md).
60 60
 By default, Docker users pull images from Docker's public registry instance.
61 61
 [Installing Docker](https://docs.docker.com/engine/installation/) gives users this
62 62
 ability. Users can also push images to a repository on Docker's public registry,
63
-if they have a [Docker Hub](https://hub.docker.com/) account. 
63
+if they have a [Docker Hub](https://hub.docker.com/) account.
64 64
 
65 65
 For some users and even companies, this default behavior is sufficient. For
66
-others, it is not. 
66
+others, it is not.
67 67
 
68 68
 For example, users with their own software products may want to maintain a
69 69
 registry for private, company images. Also, you may wish to deploy your own
70 70
 image repository for images used to test or in continuous integration. For these
71
-use cases and others, [deploying your own registry instance](docs/deploying.md)
71
+use cases and others, [deploying your own registry instance](https://github.com/docker/docker.github.io/blob/master/registry/deploying.md)
72 72
 may be the better choice.
73 73
 
74 74
 ### Migration to Registry 2.0
... ...
@@ -83,7 +83,7 @@ created. For more information see [docker/migrator]
83 83
 
84 84
 Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute
85 85
 issues, fixes, and patches to this project. If you are contributing code, see
86
-the instructions for [building a development environment](docs/recipes/building.md).
86
+the instructions for [building a development environment](BUILDING.md).
87 87
 
88 88
 ## Support
89 89
 
... ...
@@ -9,11 +9,10 @@ import (
9 9
 
10 10
 	"github.com/docker/distribution"
11 11
 	"github.com/docker/distribution/context"
12
-	"github.com/docker/distribution/reference"
13
-	"github.com/docker/libtrust"
14
-
15 12
 	"github.com/docker/distribution/digest"
16 13
 	"github.com/docker/distribution/manifest"
14
+	"github.com/docker/distribution/reference"
15
+	"github.com/docker/libtrust"
17 16
 )
18 17
 
19 18
 type diffID digest.Digest
... ...
@@ -95,7 +94,7 @@ func (mb *configManifestBuilder) Build(ctx context.Context) (m distribution.Mani
95 95
 	}
96 96
 
97 97
 	if len(img.RootFS.DiffIDs) != len(mb.descriptors) {
98
-		return nil, errors.New("number of descriptors and number of layers in rootfs must match")
98
+		return nil, fmt.Errorf("number of descriptors and number of layers in rootfs must match: len(%v) != len(%v)", img.RootFS.DiffIDs, mb.descriptors)
99 99
 	}
100 100
 
101 101
 	// Generate IDs for each layer
... ...
@@ -18,7 +18,7 @@ const (
18 18
 	MediaTypeConfig = "application/vnd.docker.container.image.v1+json"
19 19
 
20 20
 	// MediaTypePluginConfig specifies the mediaType for plugin configuration.
21
-	MediaTypePluginConfig = "application/vnd.docker.plugin.v0+json"
21
+	MediaTypePluginConfig = "application/vnd.docker.plugin.image.v0+json"
22 22
 
23 23
 	// MediaTypeLayer is the mediaType used for layers referenced by the
24 24
 	// manifest.
... ...
@@ -69,7 +69,10 @@ type Manifest struct {
69 69
 
70 70
 // References returnes the descriptors of this manifests references.
71 71
 func (m Manifest) References() []distribution.Descriptor {
72
-	return m.Layers
72
+	references := make([]distribution.Descriptor, 0, 1+len(m.Layers))
73
+	references = append(references, m.Config)
74
+	references = append(references, m.Layers...)
75
+	return references
73 76
 }
74 77
 
75 78
 // Target returns the target of this signed manifest.
... ...
@@ -12,8 +12,13 @@ import (
12 12
 // references and an optional target
13 13
 type Manifest interface {
14 14
 	// References returns a list of objects which make up this manifest.
15
-	// The references are strictly ordered from base to head. A reference
16
-	// is anything which can be represented by a distribution.Descriptor
15
+	// A reference is anything which can be represented by a
16
+	// distribution.Descriptor. These can consist of layers, resources or other
17
+	// manifests.
18
+	//
19
+	// While no particular order is required, implementations should return
20
+	// them from highest to lowest priority. For example, one might want to
21
+	// return the base layer before the top layer.
17 22
 	References() []Descriptor
18 23
 
19 24
 	// Payload provides the serialized format of the manifest, in addition to
... ...
@@ -36,6 +41,9 @@ type ManifestBuilder interface {
36 36
 	// AppendReference includes the given object in the manifest after any
37 37
 	// existing dependencies. If the add fails, such as when adding an
38 38
 	// unsupported dependency, an error may be returned.
39
+	//
40
+	// The destination of the reference is dependent on the manifest type and
41
+	// the dependency type.
39 42
 	AppendReference(dependency Describable) error
40 43
 }
41 44
 
... ...
@@ -24,6 +24,7 @@ package reference
24 24
 import (
25 25
 	"errors"
26 26
 	"fmt"
27
+	"strings"
27 28
 
28 29
 	"github.com/docker/distribution/digest"
29 30
 )
... ...
@@ -43,6 +44,9 @@ var (
43 43
 	// ErrDigestInvalidFormat represents an error while trying to parse a string as a tag.
44 44
 	ErrDigestInvalidFormat = errors.New("invalid digest format")
45 45
 
46
+	// ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters.
47
+	ErrNameContainsUppercase = errors.New("repository name must be lowercase")
48
+
46 49
 	// ErrNameEmpty is returned for empty, invalid repository names.
47 50
 	ErrNameEmpty = errors.New("repository name must have at least one component")
48 51
 
... ...
@@ -134,7 +138,7 @@ type Canonical interface {
134 134
 func SplitHostname(named Named) (string, string) {
135 135
 	name := named.Name()
136 136
 	match := anchoredNameRegexp.FindStringSubmatch(name)
137
-	if match == nil || len(match) != 3 {
137
+	if len(match) != 3 {
138 138
 		return "", name
139 139
 	}
140 140
 	return match[1], match[2]
... ...
@@ -149,7 +153,9 @@ func Parse(s string) (Reference, error) {
149 149
 		if s == "" {
150 150
 			return nil, ErrNameEmpty
151 151
 		}
152
-		// TODO(dmcgowan): Provide more specific and helpful error
152
+		if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil {
153
+			return nil, ErrNameContainsUppercase
154
+		}
153 155
 		return nil, ErrReferenceInvalidFormat
154 156
 	}
155 157
 
156 158
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+package auth
1
+
2
+import (
3
+	"net/url"
4
+	"strings"
5
+)
6
+
7
+// FROM: https://golang.org/src/net/http/http.go
8
+// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
9
+// return true if the string includes a port.
10
+func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
11
+
12
+// FROM: http://golang.org/src/net/http/transport.go
13
+var portMap = map[string]string{
14
+	"http":  "80",
15
+	"https": "443",
16
+}
17
+
18
+// canonicalAddr returns url.Host but always with a ":port" suffix
19
+// FROM: http://golang.org/src/net/http/transport.go
20
+func canonicalAddr(url *url.URL) string {
21
+	addr := url.Host
22
+	if !hasPort(addr) {
23
+		return addr + ":" + portMap[url.Scheme]
24
+	}
25
+	return addr
26
+}
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"net/http"
6 6
 	"net/url"
7 7
 	"strings"
8
+	"sync"
8 9
 )
9 10
 
10 11
 // Challenge carries information from a WWW-Authenticate response header.
... ...
@@ -43,29 +44,45 @@ type ChallengeManager interface {
43 43
 // perform requests on the endpoints or cache the responses
44 44
 // to a backend.
45 45
 func NewSimpleChallengeManager() ChallengeManager {
46
-	return simpleChallengeManager{}
46
+	return &simpleChallengeManager{
47
+		Challanges: make(map[string][]Challenge),
48
+	}
47 49
 }
48 50
 
49
-type simpleChallengeManager map[string][]Challenge
51
+type simpleChallengeManager struct {
52
+	sync.RWMutex
53
+	Challanges map[string][]Challenge
54
+}
50 55
 
51
-func (m simpleChallengeManager) GetChallenges(endpoint url.URL) ([]Challenge, error) {
56
+func normalizeURL(endpoint *url.URL) {
52 57
 	endpoint.Host = strings.ToLower(endpoint.Host)
58
+	endpoint.Host = canonicalAddr(endpoint)
59
+}
53 60
 
54
-	challenges := m[endpoint.String()]
61
+func (m *simpleChallengeManager) GetChallenges(endpoint url.URL) ([]Challenge, error) {
62
+	normalizeURL(&endpoint)
63
+
64
+	m.RLock()
65
+	defer m.RUnlock()
66
+	challenges := m.Challanges[endpoint.String()]
55 67
 	return challenges, nil
56 68
 }
57 69
 
58
-func (m simpleChallengeManager) AddResponse(resp *http.Response) error {
70
+func (m *simpleChallengeManager) AddResponse(resp *http.Response) error {
59 71
 	challenges := ResponseChallenges(resp)
60 72
 	if resp.Request == nil {
61 73
 		return fmt.Errorf("missing request reference")
62 74
 	}
63 75
 	urlCopy := url.URL{
64 76
 		Path:   resp.Request.URL.Path,
65
-		Host:   strings.ToLower(resp.Request.URL.Host),
77
+		Host:   resp.Request.URL.Host,
66 78
 		Scheme: resp.Request.URL.Scheme,
67 79
 	}
68
-	m[urlCopy.String()] = challenges
80
+	normalizeURL(&urlCopy)
81
+
82
+	m.Lock()
83
+	defer m.Unlock()
84
+	m.Challanges[urlCopy.String()] = challenges
69 85
 	return nil
70 86
 }
71 87
 
... ...
@@ -301,18 +301,20 @@ func (t *tags) Get(ctx context.Context, tag string) (distribution.Descriptor, er
301 301
 		return distribution.Descriptor{}, err
302 302
 	}
303 303
 
304
-	req, err := http.NewRequest("HEAD", u, nil)
305
-	if err != nil {
306
-		return distribution.Descriptor{}, err
307
-	}
304
+	newRequest := func(method string) (*http.Response, error) {
305
+		req, err := http.NewRequest(method, u, nil)
306
+		if err != nil {
307
+			return nil, err
308
+		}
308 309
 
309
-	for _, t := range distribution.ManifestMediaTypes() {
310
-		req.Header.Add("Accept", t)
310
+		for _, t := range distribution.ManifestMediaTypes() {
311
+			req.Header.Add("Accept", t)
312
+		}
313
+		resp, err := t.client.Do(req)
314
+		return resp, err
311 315
 	}
312 316
 
313
-	var attempts int
314
-	resp, err := t.client.Do(req)
315
-check:
317
+	resp, err := newRequest("HEAD")
316 318
 	if err != nil {
317 319
 		return distribution.Descriptor{}, err
318 320
 	}
... ...
@@ -321,23 +323,20 @@ check:
321 321
 	switch {
322 322
 	case resp.StatusCode >= 200 && resp.StatusCode < 400:
323 323
 		return descriptorFromResponse(resp)
324
-	case resp.StatusCode == http.StatusMethodNotAllowed:
325
-		req, err = http.NewRequest("GET", u, nil)
324
+	default:
325
+		// if the response is an error - there will be no body to decode.
326
+		// Issue a GET request:
327
+		//   - for data from a server that does not handle HEAD
328
+		//   - to get error details in case of a failure
329
+		resp, err = newRequest("GET")
326 330
 		if err != nil {
327 331
 			return distribution.Descriptor{}, err
328 332
 		}
333
+		defer resp.Body.Close()
329 334
 
330
-		for _, t := range distribution.ManifestMediaTypes() {
331
-			req.Header.Add("Accept", t)
332
-		}
333
-
334
-		resp, err = t.client.Do(req)
335
-		attempts++
336
-		if attempts > 1 {
337
-			return distribution.Descriptor{}, err
335
+		if resp.StatusCode >= 200 && resp.StatusCode < 400 {
336
+			return descriptorFromResponse(resp)
338 337
 		}
339
-		goto check
340
-	default:
341 338
 		return distribution.Descriptor{}, HandleErrorResponse(resp)
342 339
 	}
343 340
 }
... ...
@@ -181,6 +181,7 @@ func (hrs *httpReadSeeker) reader() (io.Reader, error) {
181 181
 		// context.GetLogger(hrs.context).Infof("Range: %s", req.Header.Get("Range"))
182 182
 	}
183 183
 
184
+	req.Header.Add("Accept-Encoding", "identity")
184 185
 	resp, err := hrs.client.Do(req)
185 186
 	if err != nil {
186 187
 		return nil, err
... ...
@@ -77,37 +77,46 @@ type repositoryScopedInMemoryBlobDescriptorCache struct {
77 77
 }
78 78
 
79 79
 func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
80
-	if rsimbdcp.repository == nil {
80
+	rsimbdcp.parent.mu.Lock()
81
+	repo := rsimbdcp.repository
82
+	rsimbdcp.parent.mu.Unlock()
83
+
84
+	if repo == nil {
81 85
 		return distribution.Descriptor{}, distribution.ErrBlobUnknown
82 86
 	}
83 87
 
84
-	return rsimbdcp.repository.Stat(ctx, dgst)
88
+	return repo.Stat(ctx, dgst)
85 89
 }
86 90
 
87 91
 func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) Clear(ctx context.Context, dgst digest.Digest) error {
88
-	if rsimbdcp.repository == nil {
92
+	rsimbdcp.parent.mu.Lock()
93
+	repo := rsimbdcp.repository
94
+	rsimbdcp.parent.mu.Unlock()
95
+
96
+	if repo == nil {
89 97
 		return distribution.ErrBlobUnknown
90 98
 	}
91 99
 
92
-	return rsimbdcp.repository.Clear(ctx, dgst)
100
+	return repo.Clear(ctx, dgst)
93 101
 }
94 102
 
95 103
 func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
96
-	if rsimbdcp.repository == nil {
104
+	rsimbdcp.parent.mu.Lock()
105
+	repo := rsimbdcp.repository
106
+	if repo == nil {
97 107
 		// allocate map since we are setting it now.
98
-		rsimbdcp.parent.mu.Lock()
99 108
 		var ok bool
100 109
 		// have to read back value since we may have allocated elsewhere.
101
-		rsimbdcp.repository, ok = rsimbdcp.parent.repositories[rsimbdcp.repo]
110
+		repo, ok = rsimbdcp.parent.repositories[rsimbdcp.repo]
102 111
 		if !ok {
103
-			rsimbdcp.repository = newMapBlobDescriptorCache()
104
-			rsimbdcp.parent.repositories[rsimbdcp.repo] = rsimbdcp.repository
112
+			repo = newMapBlobDescriptorCache()
113
+			rsimbdcp.parent.repositories[rsimbdcp.repo] = repo
105 114
 		}
106
-
107
-		rsimbdcp.parent.mu.Unlock()
115
+		rsimbdcp.repository = repo
108 116
 	}
117
+	rsimbdcp.parent.mu.Unlock()
109 118
 
110
-	if err := rsimbdcp.repository.SetDescriptor(ctx, dgst, desc); err != nil {
119
+	if err := repo.SetDescriptor(ctx, dgst, desc); err != nil {
111 120
 		return err
112 121
 	}
113 122