Add 'library/' prefix only for images belonging to Docker Hub.
Signed-off-by: Michal Minar <miminar@redhat.com>
... | ... |
@@ -21,12 +21,6 @@ import ( |
21 | 21 |
imageapi "github.com/openshift/origin/pkg/image/api" |
22 | 22 |
) |
23 | 23 |
|
24 |
-const ( |
|
25 |
- publicV1DockerHubHost = "index.docker.io" |
|
26 |
- // TODO: is there a better URL? |
|
27 |
- publicV2DockerHubHost = "registry-1.docker.io" |
|
28 |
-) |
|
29 |
- |
|
30 | 24 |
type Image struct { |
31 | 25 |
docker.Image |
32 | 26 |
|
... | ... |
@@ -40,16 +34,17 @@ type Client interface { |
40 | 40 |
Connect(registry string, allowInsecure bool) (Connection, error) |
41 | 41 |
} |
42 | 42 |
|
43 |
-// Connection allows you to retrieve data from a Docker V1 registry. |
|
43 |
+// Connection allows you to retrieve data from a Docker V1/V2 registry. |
|
44 | 44 |
type Connection interface { |
45 |
- // ImageTags will return a map of the tags for the image by namespace (if not |
|
46 |
- // specified, will be "library") and name. |
|
45 |
+ // ImageTags will return a map of the tags for the image by namespace and name. |
|
46 |
+ // If namespace is not specified, will default to "library" for Docker hub. |
|
47 | 47 |
ImageTags(namespace, name string) (map[string]string, error) |
48 |
- // ImageByID will return the requested image by namespace (if not specified, |
|
49 |
- // will be "library"), name, and ID. |
|
48 |
+ // ImageByID will return the requested image by namespace, name, and ID. |
|
49 |
+ // If namespace is not specified, will default to "library" for Docker hub. |
|
50 | 50 |
ImageByID(namespace, name, id string) (*Image, error) |
51 |
- // ImageByTag will return the requested image by namespace (if not specified, |
|
52 |
- // will be "library"), name, and tag (if not specified, "latest"). |
|
51 |
+ // ImageByTag will return the requested image by namespace, name, and tag |
|
52 |
+ // (if not specified, "latest"). |
|
53 |
+ // If namespace is not specified, will default to "library" for Docker hub. |
|
53 | 54 |
ImageByTag(namespace, name, tag string) (*Image, error) |
54 | 55 |
} |
55 | 56 |
|
... | ... |
@@ -91,11 +86,11 @@ func (c *client) Connect(name string, allowInsecure bool) (Connection, error) { |
91 | 91 |
// segment and docker API version. |
92 | 92 |
func normalizeDockerHubHost(host string, v2 bool) string { |
93 | 93 |
switch host { |
94 |
- case "docker.io", "www.docker.io", publicV1DockerHubHost, publicV2DockerHubHost: |
|
94 |
+ case imageapi.DockerDefaultRegistry, "www." + imageapi.DockerDefaultRegistry, imageapi.DockerDefaultV1Registry, imageapi.DockerDefaultV2Registry: |
|
95 | 95 |
if v2 { |
96 |
- return publicV2DockerHubHost |
|
96 |
+ return imageapi.DockerDefaultV2Registry |
|
97 | 97 |
} |
98 |
- return publicV1DockerHubHost |
|
98 |
+ return imageapi.DockerDefaultV1Registry |
|
99 | 99 |
} |
100 | 100 |
return host |
101 | 101 |
} |
... | ... |
@@ -105,7 +100,7 @@ func normalizeDockerHubHost(host string, v2 bool) string { |
105 | 105 |
func normalizeRegistryName(name string) (*url.URL, error) { |
106 | 106 |
prefix := name |
107 | 107 |
if len(prefix) == 0 { |
108 |
- prefix = publicV1DockerHubHost |
|
108 |
+ prefix = imageapi.DockerDefaultV1Registry |
|
109 | 109 |
} |
110 | 110 |
hadPrefix := false |
111 | 111 |
switch { |
... | ... |
@@ -209,7 +204,7 @@ func newConnection(url url.URL, dialTimeout time.Duration, allowInsecure, enable |
209 | 209 |
|
210 | 210 |
// ImageTags returns the tags for the named Docker image repository. |
211 | 211 |
func (c *connection) ImageTags(namespace, name string) (map[string]string, error) { |
212 |
- if len(namespace) == 0 { |
|
212 |
+ if len(namespace) == 0 && imageapi.IsRegistryDockerHub(c.url.Host) { |
|
213 | 213 |
namespace = imageapi.DockerDefaultNamespace |
214 | 214 |
} |
215 | 215 |
if len(name) == 0 { |
... | ... |
@@ -226,7 +221,7 @@ func (c *connection) ImageTags(namespace, name string) (map[string]string, error |
226 | 226 |
|
227 | 227 |
// ImageByID returns the specified image within the named Docker image repository |
228 | 228 |
func (c *connection) ImageByID(namespace, name, imageID string) (*Image, error) { |
229 |
- if len(namespace) == 0 { |
|
229 |
+ if len(namespace) == 0 && imageapi.IsRegistryDockerHub(c.url.Host) { |
|
230 | 230 |
namespace = imageapi.DockerDefaultNamespace |
231 | 231 |
} |
232 | 232 |
if len(name) == 0 { |
... | ... |
@@ -243,7 +238,7 @@ func (c *connection) ImageByID(namespace, name, imageID string) (*Image, error) |
243 | 243 |
|
244 | 244 |
// ImageByTag returns the specified image within the named Docker image repository |
245 | 245 |
func (c *connection) ImageByTag(namespace, name, tag string) (*Image, error) { |
246 |
- if len(namespace) == 0 { |
|
246 |
+ if len(namespace) == 0 && imageapi.IsRegistryDockerHub(c.url.Host) { |
|
247 | 247 |
namespace = imageapi.DockerDefaultNamespace |
248 | 248 |
} |
249 | 249 |
if len(name) == 0 { |
... | ... |
@@ -18,6 +18,10 @@ const ( |
18 | 18 |
DockerDefaultNamespace = "library" |
19 | 19 |
// DockerDefaultRegistry is the value for the registry when none was provided. |
20 | 20 |
DockerDefaultRegistry = "docker.io" |
21 |
+ // DockerDefaultV1Registry is the host name of the default v1 registry |
|
22 |
+ DockerDefaultV1Registry = "index." + DockerDefaultRegistry |
|
23 |
+ // DockerDefaultV2Registry is the host name of the default v2 registry |
|
24 |
+ DockerDefaultV2Registry = "registry-1." + DockerDefaultRegistry |
|
21 | 25 |
) |
22 | 26 |
|
23 | 27 |
// TODO remove (base, tag, id) |
... | ... |
@@ -47,6 +51,17 @@ func isRegistryName(str string) bool { |
47 | 47 |
return false |
48 | 48 |
} |
49 | 49 |
|
50 |
+// IsRegistryDockerHub returns true if the given registry name belongs to |
|
51 |
+// Docker hub. |
|
52 |
+func IsRegistryDockerHub(registry string) bool { |
|
53 |
+ switch registry { |
|
54 |
+ case DockerDefaultRegistry, DockerDefaultV1Registry, DockerDefaultV2Registry: |
|
55 |
+ return true |
|
56 |
+ default: |
|
57 |
+ return false |
|
58 |
+ } |
|
59 |
+} |
|
60 |
+ |
|
50 | 61 |
// ParseDockerImageReference parses a Docker pull spec string into a |
51 | 62 |
// DockerImageReference. |
52 | 63 |
func ParseDockerImageReference(spec string) (DockerImageReference, error) { |
... | ... |
@@ -60,8 +75,9 @@ func ParseDockerImageReference(spec string) (DockerImageReference, error) { |
60 | 60 |
if isRegistryName(repoParts[0]) { |
61 | 61 |
// registry/name |
62 | 62 |
ref.Registry = repoParts[0] |
63 |
- // TODO: default this in all cases where Namespace ends up as ""? |
|
64 |
- ref.Namespace = DockerDefaultNamespace |
|
63 |
+ if IsRegistryDockerHub(ref.Registry) { |
|
64 |
+ ref.Namespace = DockerDefaultNamespace |
|
65 |
+ } |
|
65 | 66 |
if len(repoParts[1]) == 0 { |
66 | 67 |
return ref, fmt.Errorf("the docker pull spec %q must be two or three segments separated by slashes", spec) |
67 | 68 |
} |
... | ... |
@@ -117,12 +133,12 @@ func (r DockerImageReference) Equal(other DockerImageReference) bool { |
117 | 117 |
|
118 | 118 |
// DockerClientDefaults sets the default values used by the Docker client. |
119 | 119 |
func (r DockerImageReference) DockerClientDefaults() DockerImageReference { |
120 |
- if len(r.Namespace) == 0 { |
|
121 |
- r.Namespace = DockerDefaultNamespace |
|
122 |
- } |
|
123 | 120 |
if len(r.Registry) == 0 { |
124 | 121 |
r.Registry = DockerDefaultRegistry |
125 | 122 |
} |
123 |
+ if len(r.Namespace) == 0 && IsRegistryDockerHub(r.Registry) { |
|
124 |
+ r.Namespace = DockerDefaultNamespace |
|
125 |
+ } |
|
126 | 126 |
if len(r.Tag) == 0 { |
127 | 127 |
r.Tag = DefaultImageTag |
128 | 128 |
} |
... | ... |
@@ -150,8 +166,8 @@ func (r DockerImageReference) DaemonMinimal() DockerImageReference { |
150 | 150 |
r.Namespace = "" |
151 | 151 |
} |
152 | 152 |
switch r.Registry { |
153 |
- case "index.docker.io", "docker.io": |
|
154 |
- r.Registry = "docker.io" |
|
153 |
+ case DockerDefaultV1Registry, DockerDefaultV2Registry: |
|
154 |
+ r.Registry = DockerDefaultRegistry |
|
155 | 155 |
} |
156 | 156 |
return r.Minimal() |
157 | 157 |
} |
... | ... |
@@ -198,7 +214,7 @@ func (r DockerImageReference) Exact() string { |
198 | 198 |
// String converts a DockerImageReference to a Docker pull spec (which implies a default namespace |
199 | 199 |
// according to V1 Docker registry rules). Use Exact() if you want no defaulting. |
200 | 200 |
func (r DockerImageReference) String() string { |
201 |
- if len(r.Namespace) == 0 { |
|
201 |
+ if len(r.Namespace) == 0 && IsRegistryDockerHub(r.Registry) { |
|
202 | 202 |
r.Namespace = DockerDefaultNamespace |
203 | 203 |
} |
204 | 204 |
return r.Exact() |
... | ... |
@@ -56,6 +56,12 @@ func TestParseDockerImageReference(t *testing.T) { |
56 | 56 |
Name: "baz", |
57 | 57 |
}, |
58 | 58 |
{ |
59 |
+ From: "bar/library/baz", |
|
60 |
+ Registry: "bar", |
|
61 |
+ Namespace: "library", |
|
62 |
+ Name: "baz", |
|
63 |
+ }, |
|
64 |
+ { |
|
59 | 65 |
From: "bar/foo/baz:tag", |
60 | 66 |
Registry: "bar", |
61 | 67 |
Namespace: "foo", |
... | ... |
@@ -76,12 +82,17 @@ func TestParseDockerImageReference(t *testing.T) { |
76 | 76 |
Name: "baz", |
77 | 77 |
}, |
78 | 78 |
{ |
79 |
- From: "bar:5000/baz", |
|
79 |
+ From: "bar:5000/library/baz", |
|
80 | 80 |
Registry: "bar:5000", |
81 |
- Namespace: DockerDefaultNamespace, |
|
81 |
+ Namespace: "library", |
|
82 | 82 |
Name: "baz", |
83 | 83 |
}, |
84 | 84 |
{ |
85 |
+ From: "bar:5000/baz", |
|
86 |
+ Registry: "bar:5000", |
|
87 |
+ Name: "baz", |
|
88 |
+ }, |
|
89 |
+ { |
|
85 | 90 |
From: "bar:5000/foo/baz:tag", |
86 | 91 |
Registry: "bar:5000", |
87 | 92 |
Namespace: "foo", |
... | ... |
@@ -96,14 +107,36 @@ func TestParseDockerImageReference(t *testing.T) { |
96 | 96 |
ID: "sha256:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
97 | 97 |
}, |
98 | 98 |
{ |
99 |
- From: "myregistry.io/foo", |
|
100 |
- Registry: "myregistry.io", |
|
99 |
+ From: "myregistry.io/foo", |
|
100 |
+ Registry: "myregistry.io", |
|
101 |
+ Name: "foo", |
|
102 |
+ }, |
|
103 |
+ { |
|
104 |
+ From: "localhost/bar", |
|
105 |
+ Registry: "localhost", |
|
106 |
+ Name: "bar", |
|
107 |
+ }, |
|
108 |
+ { |
|
109 |
+ From: "docker.io/library/myapp", |
|
110 |
+ Registry: "docker.io", |
|
111 |
+ Namespace: "library", |
|
112 |
+ Name: "myapp", |
|
113 |
+ }, |
|
114 |
+ { |
|
115 |
+ From: "docker.io/myapp", |
|
116 |
+ Registry: "docker.io", |
|
101 | 117 |
Namespace: DockerDefaultNamespace, |
102 |
- Name: "foo", |
|
118 |
+ Name: "myapp", |
|
103 | 119 |
}, |
104 | 120 |
{ |
105 |
- From: "localhost/bar", |
|
106 |
- Registry: "localhost", |
|
121 |
+ From: "docker.io/user/myapp", |
|
122 |
+ Registry: "docker.io", |
|
123 |
+ Namespace: "user", |
|
124 |
+ Name: "myapp", |
|
125 |
+ }, |
|
126 |
+ { |
|
127 |
+ From: "index.docker.io/bar", |
|
128 |
+ Registry: "index.docker.io", |
|
107 | 129 |
Namespace: DockerDefaultNamespace, |
108 | 130 |
Name: "bar", |
109 | 131 |
}, |
... | ... |
@@ -238,22 +271,22 @@ func TestDockerImageReferenceString(t *testing.T) { |
238 | 238 |
}{ |
239 | 239 |
{ |
240 | 240 |
Name: "foo", |
241 |
- Expected: "library/foo", |
|
241 |
+ Expected: "foo", |
|
242 | 242 |
}, |
243 | 243 |
{ |
244 | 244 |
Name: "foo", |
245 | 245 |
Tag: "tag", |
246 |
- Expected: "library/foo:tag", |
|
246 |
+ Expected: "foo:tag", |
|
247 | 247 |
}, |
248 | 248 |
{ |
249 | 249 |
Name: "foo", |
250 | 250 |
ID: "sha256:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
251 |
- Expected: "library/foo@sha256:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
|
251 |
+ Expected: "foo@sha256:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
|
252 | 252 |
}, |
253 | 253 |
{ |
254 | 254 |
Name: "foo", |
255 | 255 |
ID: "3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
256 |
- Expected: "library/foo:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
|
256 |
+ Expected: "foo:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
|
257 | 257 |
}, |
258 | 258 |
{ |
259 | 259 |
Namespace: "bar", |
... | ... |
@@ -307,11 +340,36 @@ func TestDockerImageReferenceString(t *testing.T) { |
307 | 307 |
}, |
308 | 308 |
{ |
309 | 309 |
Registry: "bar:5000", |
310 |
+ Namespace: "library", |
|
311 |
+ Name: "baz", |
|
312 |
+ Tag: "tag", |
|
313 |
+ Expected: "bar:5000/library/baz:tag", |
|
314 |
+ }, |
|
315 |
+ { |
|
316 |
+ Registry: "bar:5000", |
|
310 | 317 |
Namespace: "foo", |
311 | 318 |
Name: "baz", |
312 | 319 |
ID: "sha256:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
313 | 320 |
Expected: "bar:5000/foo/baz@sha256:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
314 | 321 |
}, |
322 |
+ { |
|
323 |
+ Registry: "docker.io", |
|
324 |
+ Namespace: "user", |
|
325 |
+ Name: "app", |
|
326 |
+ Expected: "docker.io/user/app", |
|
327 |
+ }, |
|
328 |
+ { |
|
329 |
+ Registry: "index.docker.io", |
|
330 |
+ Name: "foo", |
|
331 |
+ Expected: "index.docker.io/library/foo", |
|
332 |
+ }, |
|
333 |
+ { |
|
334 |
+ Registry: "index.docker.io", |
|
335 |
+ Namespace: "library", |
|
336 |
+ Name: "bar", |
|
337 |
+ ID: "sha256:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
|
338 |
+ Expected: "index.docker.io/library/bar@sha256:3c87c572822935df60f0f5d3665bd376841a7fcfeb806b5f212de6a00e9a7b25", |
|
339 |
+ }, |
|
315 | 340 |
} |
316 | 341 |
|
317 | 342 |
for i, testCase := range testCases { |
... | ... |
@@ -36,7 +36,7 @@ os::cmd::expect_success 'oc delete is/binary-test bc/binary-test' |
36 | 36 |
|
37 | 37 |
# Build from Dockerfile with output to DockerImage |
38 | 38 |
os::cmd::expect_success "oc new-build -D \$'FROM openshift/origin:v1.1' --to-docker" |
39 |
-os::cmd::expect_success_and_text "oc get bc/origin --template '${template}'" '^DockerImage library/origin:latest$' |
|
39 |
+os::cmd::expect_success_and_text "oc get bc/origin --template '${template}'" '^DockerImage origin:latest$' |
|
40 | 40 |
|
41 | 41 |
os::cmd::expect_success 'oc delete is/origin' |
42 | 42 |
|
... | ... |
@@ -15,13 +15,13 @@ os::cmd::expect_success_and_text 'oc new-app library/php mysql -o yaml' '3306' |
15 | 15 |
os::cmd::expect_success_and_text 'oc new-app library/php mysql --dry-run' "Image \"mysql\" runs as the 'root' user which may not be permitted by your cluster administrator" |
16 | 16 |
os::cmd::expect_failure 'oc new-app unknownhubimage -o yaml' |
17 | 17 |
# verify we can generate a Docker image based component "mongodb" directly |
18 |
-os::cmd::expect_success_and_text 'oc new-app mongo -o yaml' 'library/mongo' |
|
18 |
+os::cmd::expect_success_and_text 'oc new-app mongo -o yaml' 'image:\s*mongo' |
|
19 | 19 |
# the local image repository takes precedence over the Docker Hub "mysql" image |
20 | 20 |
os::cmd::expect_success 'oc create -f examples/image-streams/image-streams-centos7.json' |
21 | 21 |
os::cmd::try_until_success 'oc get imagestreamtags mysql:latest' |
22 | 22 |
os::cmd::try_until_success 'oc get imagestreamtags mysql:5.5' |
23 | 23 |
os::cmd::try_until_success 'oc get imagestreamtags mysql:5.6' |
24 |
-os::cmd::expect_success_and_not_text 'oc new-app mysql -o yaml' 'library/mysql' |
|
24 |
+os::cmd::expect_success_and_not_text 'oc new-app mysql -o yaml' 'image:\s*mysql' |
|
25 | 25 |
os::cmd::expect_success_and_not_text 'oc new-app mysql --dry-run' "runs as the 'root' user which may not be permitted by your cluster administrator" |
26 | 26 |
|
27 | 27 |
# docker strategy with repo that has no dockerfile |