[test-integration] Add a registry package with registry v1/v2 code
Sebastiaan van Stijn authored on 2017/01/02 23:37:09... | ... |
@@ -16,6 +16,7 @@ import ( |
16 | 16 |
cliconfig "github.com/docker/docker/cli/config" |
17 | 17 |
"github.com/docker/docker/integration-cli/daemon" |
18 | 18 |
"github.com/docker/docker/integration-cli/environment" |
19 |
+ "github.com/docker/docker/integration-cli/registry" |
|
19 | 20 |
"github.com/docker/docker/pkg/reexec" |
20 | 21 |
"github.com/go-check/check" |
21 | 22 |
) |
... | ... |
@@ -172,7 +173,7 @@ func init() { |
172 | 172 |
|
173 | 173 |
type DockerRegistrySuite struct { |
174 | 174 |
ds *DockerSuite |
175 |
- reg *testRegistryV2 |
|
175 |
+ reg *registry.V2 |
|
176 | 176 |
d *daemon.Daemon |
177 | 177 |
} |
178 | 178 |
|
... | ... |
@@ -181,7 +182,7 @@ func (s *DockerRegistrySuite) OnTimeout(c *check.C) { |
181 | 181 |
} |
182 | 182 |
|
183 | 183 |
func (s *DockerRegistrySuite) SetUpTest(c *check.C) { |
184 |
- testRequires(c, DaemonIsLinux, RegistryHosting) |
|
184 |
+ testRequires(c, DaemonIsLinux, registry.Hosting) |
|
185 | 185 |
s.reg = setupRegistry(c, false, "", "") |
186 | 186 |
s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ |
187 | 187 |
Experimental: experimentalDaemon, |
... | ... |
@@ -206,7 +207,7 @@ func init() { |
206 | 206 |
|
207 | 207 |
type DockerSchema1RegistrySuite struct { |
208 | 208 |
ds *DockerSuite |
209 |
- reg *testRegistryV2 |
|
209 |
+ reg *registry.V2 |
|
210 | 210 |
d *daemon.Daemon |
211 | 211 |
} |
212 | 212 |
|
... | ... |
@@ -215,7 +216,7 @@ func (s *DockerSchema1RegistrySuite) OnTimeout(c *check.C) { |
215 | 215 |
} |
216 | 216 |
|
217 | 217 |
func (s *DockerSchema1RegistrySuite) SetUpTest(c *check.C) { |
218 |
- testRequires(c, DaemonIsLinux, RegistryHosting, NotArm64) |
|
218 |
+ testRequires(c, DaemonIsLinux, registry.Hosting, NotArm64) |
|
219 | 219 |
s.reg = setupRegistry(c, true, "", "") |
220 | 220 |
s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ |
221 | 221 |
Experimental: experimentalDaemon, |
... | ... |
@@ -240,7 +241,7 @@ func init() { |
240 | 240 |
|
241 | 241 |
type DockerRegistryAuthHtpasswdSuite struct { |
242 | 242 |
ds *DockerSuite |
243 |
- reg *testRegistryV2 |
|
243 |
+ reg *registry.V2 |
|
244 | 244 |
d *daemon.Daemon |
245 | 245 |
} |
246 | 246 |
|
... | ... |
@@ -249,7 +250,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) OnTimeout(c *check.C) { |
249 | 249 |
} |
250 | 250 |
|
251 | 251 |
func (s *DockerRegistryAuthHtpasswdSuite) SetUpTest(c *check.C) { |
252 |
- testRequires(c, DaemonIsLinux, RegistryHosting) |
|
252 |
+ testRequires(c, DaemonIsLinux, registry.Hosting) |
|
253 | 253 |
s.reg = setupRegistry(c, false, "htpasswd", "") |
254 | 254 |
s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ |
255 | 255 |
Experimental: experimentalDaemon, |
... | ... |
@@ -276,7 +277,7 @@ func init() { |
276 | 276 |
|
277 | 277 |
type DockerRegistryAuthTokenSuite struct { |
278 | 278 |
ds *DockerSuite |
279 |
- reg *testRegistryV2 |
|
279 |
+ reg *registry.V2 |
|
280 | 280 |
d *daemon.Daemon |
281 | 281 |
} |
282 | 282 |
|
... | ... |
@@ -285,7 +286,7 @@ func (s *DockerRegistryAuthTokenSuite) OnTimeout(c *check.C) { |
285 | 285 |
} |
286 | 286 |
|
287 | 287 |
func (s *DockerRegistryAuthTokenSuite) SetUpTest(c *check.C) { |
288 |
- testRequires(c, DaemonIsLinux, RegistryHosting) |
|
288 |
+ testRequires(c, DaemonIsLinux, registry.Hosting) |
|
289 | 289 |
s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ |
290 | 290 |
Experimental: experimentalDaemon, |
291 | 291 |
}) |
... | ... |
@@ -449,12 +450,12 @@ func init() { |
449 | 449 |
|
450 | 450 |
type DockerTrustSuite struct { |
451 | 451 |
ds *DockerSuite |
452 |
- reg *testRegistryV2 |
|
452 |
+ reg *registry.V2 |
|
453 | 453 |
not *testNotary |
454 | 454 |
} |
455 | 455 |
|
456 | 456 |
func (s *DockerTrustSuite) SetUpTest(c *check.C) { |
457 |
- testRequires(c, RegistryHosting, NotaryServerHosting) |
|
457 |
+ testRequires(c, registry.Hosting, NotaryServerHosting) |
|
458 | 458 |
s.reg = setupRegistry(c, false, "", "") |
459 | 459 |
s.not = setupNotary(c) |
460 | 460 |
} |
... | ... |
@@ -487,7 +488,7 @@ func init() { |
487 | 487 |
type DockerTrustedSwarmSuite struct { |
488 | 488 |
swarmSuite DockerSwarmSuite |
489 | 489 |
trustSuite DockerTrustSuite |
490 |
- reg *testRegistryV2 |
|
490 |
+ reg *registry.V2 |
|
491 | 491 |
not *testNotary |
492 | 492 |
} |
493 | 493 |
|
... | ... |
@@ -6580,7 +6580,7 @@ func (s *DockerSuite) TestBuildLabelOverwrite(c *check.C) { |
6580 | 6580 |
} |
6581 | 6581 |
|
6582 | 6582 |
func (s *DockerRegistryAuthHtpasswdSuite) TestBuildFromAuthenticatedRegistry(c *check.C) { |
6583 |
- dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) |
|
6583 |
+ dockerCmd(c, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) |
|
6584 | 6584 |
|
6585 | 6585 |
baseImage := privateRegistryURL + "/baseimage" |
6586 | 6586 |
|
... | ... |
@@ -6625,7 +6625,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestBuildWithExternalAuth(c *check.C) |
6625 | 6625 |
err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) |
6626 | 6626 |
c.Assert(err, checker.IsNil) |
6627 | 6627 |
|
6628 |
- dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) |
|
6628 |
+ dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) |
|
6629 | 6629 |
|
6630 | 6630 |
b, err := ioutil.ReadFile(configPath) |
6631 | 6631 |
c.Assert(err, checker.IsNil) |
... | ... |
@@ -533,7 +533,7 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) { |
533 | 533 |
c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) |
534 | 534 |
|
535 | 535 |
// Load the target manifest blob. |
536 |
- manifestBlob := s.reg.readBlobContents(c, manifestDigest) |
|
536 |
+ manifestBlob := s.reg.ReadBlobContents(c, manifestDigest) |
|
537 | 537 |
|
538 | 538 |
var imgManifest schema2.Manifest |
539 | 539 |
err = json.Unmarshal(manifestBlob, &imgManifest) |
... | ... |
@@ -544,13 +544,13 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) { |
544 | 544 |
|
545 | 545 |
// Move the existing data file aside, so that we can replace it with a |
546 | 546 |
// malicious blob of data. NOTE: we defer the returned undo func. |
547 |
- undo := s.reg.tempMoveBlobData(c, manifestDigest) |
|
547 |
+ undo := s.reg.TempMoveBlobData(c, manifestDigest) |
|
548 | 548 |
defer undo() |
549 | 549 |
|
550 | 550 |
alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ") |
551 | 551 |
c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON")) |
552 | 552 |
|
553 |
- s.reg.writeBlobContents(c, manifestDigest, alteredManifestBlob) |
|
553 |
+ s.reg.WriteBlobContents(c, manifestDigest, alteredManifestBlob) |
|
554 | 554 |
|
555 | 555 |
// Now try pulling that image by digest. We should get an error about |
556 | 556 |
// digest verification for the manifest digest. |
... | ... |
@@ -573,7 +573,7 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C |
573 | 573 |
c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) |
574 | 574 |
|
575 | 575 |
// Load the target manifest blob. |
576 |
- manifestBlob := s.reg.readBlobContents(c, manifestDigest) |
|
576 |
+ manifestBlob := s.reg.ReadBlobContents(c, manifestDigest) |
|
577 | 577 |
|
578 | 578 |
var imgManifest schema1.Manifest |
579 | 579 |
err = json.Unmarshal(manifestBlob, &imgManifest) |
... | ... |
@@ -586,13 +586,13 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C |
586 | 586 |
|
587 | 587 |
// Move the existing data file aside, so that we can replace it with a |
588 | 588 |
// malicious blob of data. NOTE: we defer the returned undo func. |
589 |
- undo := s.reg.tempMoveBlobData(c, manifestDigest) |
|
589 |
+ undo := s.reg.TempMoveBlobData(c, manifestDigest) |
|
590 | 590 |
defer undo() |
591 | 591 |
|
592 | 592 |
alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ") |
593 | 593 |
c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON")) |
594 | 594 |
|
595 |
- s.reg.writeBlobContents(c, manifestDigest, alteredManifestBlob) |
|
595 |
+ s.reg.WriteBlobContents(c, manifestDigest, alteredManifestBlob) |
|
596 | 596 |
|
597 | 597 |
// Now try pulling that image by digest. We should get an error about |
598 | 598 |
// digest verification for the manifest digest. |
... | ... |
@@ -615,7 +615,7 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { |
615 | 615 |
c.Assert(err, checker.IsNil) |
616 | 616 |
|
617 | 617 |
// Load the target manifest blob. |
618 |
- manifestBlob := s.reg.readBlobContents(c, manifestDigest) |
|
618 |
+ manifestBlob := s.reg.ReadBlobContents(c, manifestDigest) |
|
619 | 619 |
|
620 | 620 |
var imgManifest schema2.Manifest |
621 | 621 |
err = json.Unmarshal(manifestBlob, &imgManifest) |
... | ... |
@@ -626,11 +626,11 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { |
626 | 626 |
|
627 | 627 |
// Move the existing data file aside, so that we can replace it with a |
628 | 628 |
// malicious blob of data. NOTE: we defer the returned undo func. |
629 |
- undo := s.reg.tempMoveBlobData(c, targetLayerDigest) |
|
629 |
+ undo := s.reg.TempMoveBlobData(c, targetLayerDigest) |
|
630 | 630 |
defer undo() |
631 | 631 |
|
632 | 632 |
// Now make a fake data blob in this directory. |
633 |
- s.reg.writeBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) |
|
633 |
+ s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) |
|
634 | 634 |
|
635 | 635 |
// Now try pulling that image by digest. We should get an error about |
636 | 636 |
// digest verification for the target layer digest. |
... | ... |
@@ -658,7 +658,7 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { |
658 | 658 |
c.Assert(err, checker.IsNil) |
659 | 659 |
|
660 | 660 |
// Load the target manifest blob. |
661 |
- manifestBlob := s.reg.readBlobContents(c, manifestDigest) |
|
661 |
+ manifestBlob := s.reg.ReadBlobContents(c, manifestDigest) |
|
662 | 662 |
|
663 | 663 |
var imgManifest schema1.Manifest |
664 | 664 |
err = json.Unmarshal(manifestBlob, &imgManifest) |
... | ... |
@@ -669,11 +669,11 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { |
669 | 669 |
|
670 | 670 |
// Move the existing data file aside, so that we can replace it with a |
671 | 671 |
// malicious blob of data. NOTE: we defer the returned undo func. |
672 |
- undo := s.reg.tempMoveBlobData(c, targetLayerDigest) |
|
672 |
+ undo := s.reg.TempMoveBlobData(c, targetLayerDigest) |
|
673 | 673 |
defer undo() |
674 | 674 |
|
675 | 675 |
// Now make a fake data blob in this directory. |
676 |
- s.reg.writeBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) |
|
676 |
+ s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) |
|
677 | 677 |
|
678 | 678 |
// Now try pulling that image by digest. We should get an error about |
679 | 679 |
// digest verification for the target layer digest. |
... | ... |
@@ -21,10 +21,10 @@ func (s *DockerSuite) TestLoginWithoutTTY(c *check.C) { |
21 | 21 |
|
22 | 22 |
func (s *DockerRegistryAuthHtpasswdSuite) TestLoginToPrivateRegistry(c *check.C) { |
23 | 23 |
// wrong credentials |
24 |
- out, _, err := dockerCmdWithError("login", "-u", s.reg.username, "-p", "WRONGPASSWORD", privateRegistryURL) |
|
24 |
+ out, _, err := dockerCmdWithError("login", "-u", s.reg.Username(), "-p", "WRONGPASSWORD", privateRegistryURL) |
|
25 | 25 |
c.Assert(err, checker.NotNil, check.Commentf(out)) |
26 | 26 |
c.Assert(out, checker.Contains, "401 Unauthorized") |
27 | 27 |
|
28 | 28 |
// now it's fine |
29 |
- dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) |
|
29 |
+ dockerCmd(c, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) |
|
30 | 30 |
} |
... | ... |
@@ -35,7 +35,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithExternalAuth(c *check.C) |
35 | 35 |
err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) |
36 | 36 |
c.Assert(err, checker.IsNil) |
37 | 37 |
|
38 |
- dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) |
|
38 |
+ dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) |
|
39 | 39 |
|
40 | 40 |
b, err := ioutil.ReadFile(configPath) |
41 | 41 |
c.Assert(err, checker.IsNil) |
... | ... |
@@ -71,7 +71,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithWrongHostnamesStored(c * |
71 | 71 |
os.Setenv("PATH", testPath) |
72 | 72 |
|
73 | 73 |
cmd := exec.Command("docker-credential-shell-test", "store") |
74 |
- stdin := bytes.NewReader([]byte(fmt.Sprintf(`{"ServerURL": "https://%s", "Username": "%s", "Secret": "%s"}`, privateRegistryURL, s.reg.username, s.reg.password))) |
|
74 |
+ stdin := bytes.NewReader([]byte(fmt.Sprintf(`{"ServerURL": "https://%s", "Username": "%s", "Secret": "%s"}`, privateRegistryURL, s.reg.Username(), s.reg.Password()))) |
|
75 | 75 |
cmd.Stdin = stdin |
76 | 76 |
c.Assert(cmd.Run(), checker.IsNil) |
77 | 77 |
|
... | ... |
@@ -84,7 +84,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithWrongHostnamesStored(c * |
84 | 84 |
err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) |
85 | 85 |
c.Assert(err, checker.IsNil) |
86 | 86 |
|
87 |
- dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) |
|
87 |
+ dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) |
|
88 | 88 |
|
89 | 89 |
b, err := ioutil.ReadFile(configPath) |
90 | 90 |
c.Assert(err, checker.IsNil) |
... | ... |
@@ -347,7 +347,7 @@ func (s *DockerRegistrySuite) TestPullManifestList(c *check.C) { |
347 | 347 |
manifestListDigest := digest.FromBytes(manifestListJSON) |
348 | 348 |
hexDigest := manifestListDigest.Hex() |
349 | 349 |
|
350 |
- registryV2Path := filepath.Join(s.reg.dir, "docker", "registry", "v2") |
|
350 |
+ registryV2Path := s.reg.Path() |
|
351 | 351 |
|
352 | 352 |
// Write manifest list to blob store |
353 | 353 |
blobDir := filepath.Join(registryV2Path, "blobs", "sha256", hexDigest[:2], hexDigest) |
... | ... |
@@ -411,7 +411,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuthLoginWithSchem |
411 | 411 |
err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) |
412 | 412 |
c.Assert(err, checker.IsNil) |
413 | 413 |
|
414 |
- dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) |
|
414 |
+ dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) |
|
415 | 415 |
|
416 | 416 |
b, err := ioutil.ReadFile(configPath) |
417 | 417 |
c.Assert(err, checker.IsNil) |
... | ... |
@@ -421,7 +421,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuthLoginWithSchem |
421 | 421 |
dockerCmd(c, "--config", tmp, "push", repoName) |
422 | 422 |
|
423 | 423 |
dockerCmd(c, "--config", tmp, "logout", privateRegistryURL) |
424 |
- dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, "https://"+privateRegistryURL) |
|
424 |
+ dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), "https://"+privateRegistryURL) |
|
425 | 425 |
dockerCmd(c, "--config", tmp, "pull", repoName) |
426 | 426 |
|
427 | 427 |
// likewise push should work |
... | ... |
@@ -456,7 +456,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuth(c *check.C) { |
456 | 456 |
err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) |
457 | 457 |
c.Assert(err, checker.IsNil) |
458 | 458 |
|
459 |
- dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) |
|
459 |
+ dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) |
|
460 | 460 |
|
461 | 461 |
b, err := ioutil.ReadFile(configPath) |
462 | 462 |
c.Assert(err, checker.IsNil) |
... | ... |
@@ -5,6 +5,7 @@ import ( |
5 | 5 |
"net/http" |
6 | 6 |
"regexp" |
7 | 7 |
|
8 |
+ "github.com/docker/docker/integration-cli/registry" |
|
8 | 9 |
"github.com/go-check/check" |
9 | 10 |
) |
10 | 11 |
|
... | ... |
@@ -46,8 +47,8 @@ func regexpCheckUA(c *check.C, ua string) { |
46 | 46 |
c.Assert(bMatchUpstreamUA, check.Equals, true, check.Commentf("(Upstream) Docker Client User-Agent malformed")) |
47 | 47 |
} |
48 | 48 |
|
49 |
-func registerUserAgentHandler(reg *testRegistry, result *string) { |
|
50 |
- reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { |
|
49 |
+func registerUserAgentHandler(reg *registry.Mock, result *string) { |
|
50 |
+ reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { |
|
51 | 51 |
w.WriteHeader(404) |
52 | 52 |
var ua string |
53 | 53 |
for k, v := range r.Header { |
... | ... |
@@ -70,30 +71,30 @@ func (s *DockerRegistrySuite) TestUserAgentPassThrough(c *check.C) { |
70 | 70 |
loginUA string |
71 | 71 |
) |
72 | 72 |
|
73 |
- buildReg, err := newTestRegistry(c) |
|
73 |
+ buildReg, err := registry.NewMock(c) |
|
74 | 74 |
c.Assert(err, check.IsNil) |
75 | 75 |
registerUserAgentHandler(buildReg, &buildUA) |
76 |
- buildRepoName := fmt.Sprintf("%s/busybox", buildReg.hostport) |
|
76 |
+ buildRepoName := fmt.Sprintf("%s/busybox", buildReg.URL()) |
|
77 | 77 |
|
78 |
- pullReg, err := newTestRegistry(c) |
|
78 |
+ pullReg, err := registry.NewMock(c) |
|
79 | 79 |
c.Assert(err, check.IsNil) |
80 | 80 |
registerUserAgentHandler(pullReg, &pullUA) |
81 |
- pullRepoName := fmt.Sprintf("%s/busybox", pullReg.hostport) |
|
81 |
+ pullRepoName := fmt.Sprintf("%s/busybox", pullReg.URL()) |
|
82 | 82 |
|
83 |
- pushReg, err := newTestRegistry(c) |
|
83 |
+ pushReg, err := registry.NewMock(c) |
|
84 | 84 |
c.Assert(err, check.IsNil) |
85 | 85 |
registerUserAgentHandler(pushReg, &pushUA) |
86 |
- pushRepoName := fmt.Sprintf("%s/busybox", pushReg.hostport) |
|
86 |
+ pushRepoName := fmt.Sprintf("%s/busybox", pushReg.URL()) |
|
87 | 87 |
|
88 |
- loginReg, err := newTestRegistry(c) |
|
88 |
+ loginReg, err := registry.NewMock(c) |
|
89 | 89 |
c.Assert(err, check.IsNil) |
90 | 90 |
registerUserAgentHandler(loginReg, &loginUA) |
91 | 91 |
|
92 | 92 |
s.d.Start(c, |
93 |
- "--insecure-registry", buildReg.hostport, |
|
94 |
- "--insecure-registry", pullReg.hostport, |
|
95 |
- "--insecure-registry", pushReg.hostport, |
|
96 |
- "--insecure-registry", loginReg.hostport, |
|
93 |
+ "--insecure-registry", buildReg.URL(), |
|
94 |
+ "--insecure-registry", pullReg.URL(), |
|
95 |
+ "--insecure-registry", pushReg.URL(), |
|
96 |
+ "--insecure-registry", loginReg.URL(), |
|
97 | 97 |
"--disable-legacy-registry=true") |
98 | 98 |
|
99 | 99 |
dockerfileName, cleanup1, err := makefile(fmt.Sprintf("FROM %s", buildRepoName)) |
... | ... |
@@ -102,7 +103,7 @@ func (s *DockerRegistrySuite) TestUserAgentPassThrough(c *check.C) { |
102 | 102 |
s.d.Cmd("build", "--file", dockerfileName, ".") |
103 | 103 |
regexpCheckUA(c, buildUA) |
104 | 104 |
|
105 |
- s.d.Cmd("login", "-u", "richard", "-p", "testtest", loginReg.hostport) |
|
105 |
+ s.d.Cmd("login", "-u", "richard", "-p", "testtest", loginReg.URL()) |
|
106 | 106 |
regexpCheckUA(c, loginUA) |
107 | 107 |
|
108 | 108 |
s.d.Cmd("pull", pullRepoName) |
... | ... |
@@ -6,6 +6,7 @@ import ( |
6 | 6 |
"net/http" |
7 | 7 |
"os" |
8 | 8 |
|
9 |
+ "github.com/docker/docker/integration-cli/registry" |
|
9 | 10 |
"github.com/go-check/check" |
10 | 11 |
) |
11 | 12 |
|
... | ... |
@@ -36,29 +37,29 @@ func makefile(contents string) (string, func(), error) { |
36 | 36 |
// TestV2Only ensures that a daemon in v2-only mode does not |
37 | 37 |
// attempt to contact any v1 registry endpoints. |
38 | 38 |
func (s *DockerRegistrySuite) TestV2Only(c *check.C) { |
39 |
- reg, err := newTestRegistry(c) |
|
39 |
+ reg, err := registry.NewMock(c) |
|
40 | 40 |
c.Assert(err, check.IsNil) |
41 | 41 |
|
42 |
- reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { |
|
42 |
+ reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { |
|
43 | 43 |
w.WriteHeader(404) |
44 | 44 |
}) |
45 | 45 |
|
46 |
- reg.registerHandler("/v1/.*", func(w http.ResponseWriter, r *http.Request) { |
|
46 |
+ reg.RegisterHandler("/v1/.*", func(w http.ResponseWriter, r *http.Request) { |
|
47 | 47 |
c.Fatal("V1 registry contacted") |
48 | 48 |
}) |
49 | 49 |
|
50 |
- repoName := fmt.Sprintf("%s/busybox", reg.hostport) |
|
50 |
+ repoName := fmt.Sprintf("%s/busybox", reg.URL()) |
|
51 | 51 |
|
52 |
- s.d.Start(c, "--insecure-registry", reg.hostport, "--disable-legacy-registry=true") |
|
52 |
+ s.d.Start(c, "--insecure-registry", reg.URL(), "--disable-legacy-registry=true") |
|
53 | 53 |
|
54 |
- dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport)) |
|
54 |
+ dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.URL())) |
|
55 | 55 |
c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile")) |
56 | 56 |
defer cleanup() |
57 | 57 |
|
58 | 58 |
s.d.Cmd("build", "--file", dockerfileName, ".") |
59 | 59 |
|
60 | 60 |
s.d.Cmd("run", repoName) |
61 |
- s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.hostport) |
|
61 |
+ s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.URL()) |
|
62 | 62 |
s.d.Cmd("tag", "busybox", repoName) |
63 | 63 |
s.d.Cmd("push", repoName) |
64 | 64 |
s.d.Cmd("pull", repoName) |
... | ... |
@@ -68,49 +69,49 @@ func (s *DockerRegistrySuite) TestV2Only(c *check.C) { |
68 | 68 |
// and ensure v1 endpoints are hit for the following operations: |
69 | 69 |
// login, push, pull, build & run |
70 | 70 |
func (s *DockerRegistrySuite) TestV1(c *check.C) { |
71 |
- reg, err := newTestRegistry(c) |
|
71 |
+ reg, err := registry.NewMock(c) |
|
72 | 72 |
c.Assert(err, check.IsNil) |
73 | 73 |
|
74 | 74 |
v2Pings := 0 |
75 |
- reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { |
|
75 |
+ reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { |
|
76 | 76 |
v2Pings++ |
77 | 77 |
// V2 ping 404 causes fallback to v1 |
78 | 78 |
w.WriteHeader(404) |
79 | 79 |
}) |
80 | 80 |
|
81 | 81 |
v1Pings := 0 |
82 |
- reg.registerHandler("/v1/_ping", func(w http.ResponseWriter, r *http.Request) { |
|
82 |
+ reg.RegisterHandler("/v1/_ping", func(w http.ResponseWriter, r *http.Request) { |
|
83 | 83 |
v1Pings++ |
84 | 84 |
}) |
85 | 85 |
|
86 | 86 |
v1Logins := 0 |
87 |
- reg.registerHandler("/v1/users/", func(w http.ResponseWriter, r *http.Request) { |
|
87 |
+ reg.RegisterHandler("/v1/users/", func(w http.ResponseWriter, r *http.Request) { |
|
88 | 88 |
v1Logins++ |
89 | 89 |
}) |
90 | 90 |
|
91 | 91 |
v1Repo := 0 |
92 |
- reg.registerHandler("/v1/repositories/busybox/", func(w http.ResponseWriter, r *http.Request) { |
|
92 |
+ reg.RegisterHandler("/v1/repositories/busybox/", func(w http.ResponseWriter, r *http.Request) { |
|
93 | 93 |
v1Repo++ |
94 | 94 |
}) |
95 | 95 |
|
96 |
- reg.registerHandler("/v1/repositories/busybox/images", func(w http.ResponseWriter, r *http.Request) { |
|
96 |
+ reg.RegisterHandler("/v1/repositories/busybox/images", func(w http.ResponseWriter, r *http.Request) { |
|
97 | 97 |
v1Repo++ |
98 | 98 |
}) |
99 | 99 |
|
100 |
- s.d.Start(c, "--insecure-registry", reg.hostport, "--disable-legacy-registry=false") |
|
100 |
+ s.d.Start(c, "--insecure-registry", reg.URL(), "--disable-legacy-registry=false") |
|
101 | 101 |
|
102 |
- dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport)) |
|
102 |
+ dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.URL())) |
|
103 | 103 |
c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile")) |
104 | 104 |
defer cleanup() |
105 | 105 |
|
106 | 106 |
s.d.Cmd("build", "--file", dockerfileName, ".") |
107 | 107 |
c.Assert(v1Repo, check.Equals, 1, check.Commentf("Expected v1 repository access after build")) |
108 | 108 |
|
109 |
- repoName := fmt.Sprintf("%s/busybox", reg.hostport) |
|
109 |
+ repoName := fmt.Sprintf("%s/busybox", reg.URL()) |
|
110 | 110 |
s.d.Cmd("run", repoName) |
111 | 111 |
c.Assert(v1Repo, check.Equals, 2, check.Commentf("Expected v1 repository access after run")) |
112 | 112 |
|
113 |
- s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.hostport) |
|
113 |
+ s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.URL()) |
|
114 | 114 |
c.Assert(v1Logins, check.Equals, 1, check.Commentf("Expected v1 login attempt")) |
115 | 115 |
|
116 | 116 |
s.d.Cmd("tag", "busybox", repoName) |
... | ... |
@@ -25,6 +25,7 @@ import ( |
25 | 25 |
volumetypes "github.com/docker/docker/api/types/volume" |
26 | 26 |
"github.com/docker/docker/integration-cli/checker" |
27 | 27 |
"github.com/docker/docker/integration-cli/daemon" |
28 |
+ "github.com/docker/docker/integration-cli/registry" |
|
28 | 29 |
"github.com/docker/docker/opts" |
29 | 30 |
"github.com/docker/docker/pkg/ioutils" |
30 | 31 |
"github.com/docker/docker/pkg/stringutils" |
... | ... |
@@ -1083,8 +1084,8 @@ func parseEventTime(t time.Time) string { |
1083 | 1083 |
return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())) |
1084 | 1084 |
} |
1085 | 1085 |
|
1086 |
-func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *testRegistryV2 { |
|
1087 |
- reg, err := newTestRegistryV2(c, schema1, auth, tokenURL) |
|
1086 |
+func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *registry.V2 { |
|
1087 |
+ reg, err := registry.NewV2(schema1, auth, tokenURL, privateRegistryURL) |
|
1088 | 1088 |
c.Assert(err, check.IsNil) |
1089 | 1089 |
|
1090 | 1090 |
// Wait for registry to be ready to serve requests. |
1091 | 1091 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,208 @@ |
0 |
+package registry |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "fmt" |
|
4 |
+ "io/ioutil" |
|
5 |
+ "net/http" |
|
6 |
+ "os" |
|
7 |
+ "os/exec" |
|
8 |
+ "path/filepath" |
|
9 |
+ |
|
10 |
+ "github.com/docker/distribution/digest" |
|
11 |
+) |
|
12 |
+ |
|
13 |
+const ( |
|
14 |
+ v2binary = "registry-v2" |
|
15 |
+ v2binarySchema1 = "registry-v2-schema1" |
|
16 |
+) |
|
17 |
+ |
|
18 |
+type testingT interface { |
|
19 |
+ logT |
|
20 |
+ Fatal(...interface{}) |
|
21 |
+ Fatalf(string, ...interface{}) |
|
22 |
+} |
|
23 |
+ |
|
24 |
+type logT interface { |
|
25 |
+ Logf(string, ...interface{}) |
|
26 |
+} |
|
27 |
+ |
|
28 |
+// V2 represent a registry version 2 |
|
29 |
+type V2 struct { |
|
30 |
+ cmd *exec.Cmd |
|
31 |
+ registryURL string |
|
32 |
+ dir string |
|
33 |
+ auth string |
|
34 |
+ username string |
|
35 |
+ password string |
|
36 |
+ email string |
|
37 |
+} |
|
38 |
+ |
|
39 |
+// NewV2 creates a v2 registry server |
|
40 |
+func NewV2(schema1 bool, auth, tokenURL, registryURL string) (*V2, error) { |
|
41 |
+ tmp, err := ioutil.TempDir("", "registry-test-") |
|
42 |
+ if err != nil { |
|
43 |
+ return nil, err |
|
44 |
+ } |
|
45 |
+ template := `version: 0.1 |
|
46 |
+loglevel: debug |
|
47 |
+storage: |
|
48 |
+ filesystem: |
|
49 |
+ rootdirectory: %s |
|
50 |
+http: |
|
51 |
+ addr: %s |
|
52 |
+%s` |
|
53 |
+ var ( |
|
54 |
+ authTemplate string |
|
55 |
+ username string |
|
56 |
+ password string |
|
57 |
+ email string |
|
58 |
+ ) |
|
59 |
+ switch auth { |
|
60 |
+ case "htpasswd": |
|
61 |
+ htpasswdPath := filepath.Join(tmp, "htpasswd") |
|
62 |
+ // generated with: htpasswd -Bbn testuser testpassword |
|
63 |
+ userpasswd := "testuser:$2y$05$sBsSqk0OpSD1uTZkHXc4FeJ0Z70wLQdAX/82UiHuQOKbNbBrzs63m" |
|
64 |
+ username = "testuser" |
|
65 |
+ password = "testpassword" |
|
66 |
+ email = "test@test.org" |
|
67 |
+ if err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644)); err != nil { |
|
68 |
+ return nil, err |
|
69 |
+ } |
|
70 |
+ authTemplate = fmt.Sprintf(`auth: |
|
71 |
+ htpasswd: |
|
72 |
+ realm: basic-realm |
|
73 |
+ path: %s |
|
74 |
+`, htpasswdPath) |
|
75 |
+ case "token": |
|
76 |
+ authTemplate = fmt.Sprintf(`auth: |
|
77 |
+ token: |
|
78 |
+ realm: %s |
|
79 |
+ service: "registry" |
|
80 |
+ issuer: "auth-registry" |
|
81 |
+ rootcertbundle: "fixtures/registry/cert.pem" |
|
82 |
+`, tokenURL) |
|
83 |
+ } |
|
84 |
+ |
|
85 |
+ confPath := filepath.Join(tmp, "config.yaml") |
|
86 |
+ config, err := os.Create(confPath) |
|
87 |
+ if err != nil { |
|
88 |
+ return nil, err |
|
89 |
+ } |
|
90 |
+ defer config.Close() |
|
91 |
+ |
|
92 |
+ if _, err := fmt.Fprintf(config, template, tmp, registryURL, authTemplate); err != nil { |
|
93 |
+ os.RemoveAll(tmp) |
|
94 |
+ return nil, err |
|
95 |
+ } |
|
96 |
+ |
|
97 |
+ binary := v2binary |
|
98 |
+ if schema1 { |
|
99 |
+ binary = v2binarySchema1 |
|
100 |
+ } |
|
101 |
+ cmd := exec.Command(binary, confPath) |
|
102 |
+ if err := cmd.Start(); err != nil { |
|
103 |
+ os.RemoveAll(tmp) |
|
104 |
+ return nil, err |
|
105 |
+ } |
|
106 |
+ return &V2{ |
|
107 |
+ cmd: cmd, |
|
108 |
+ dir: tmp, |
|
109 |
+ auth: auth, |
|
110 |
+ username: username, |
|
111 |
+ password: password, |
|
112 |
+ email: email, |
|
113 |
+ registryURL: registryURL, |
|
114 |
+ }, nil |
|
115 |
+} |
|
116 |
+ |
|
117 |
+// Ping sends an http request to the current registry, and fail if it doesn't respond correctly |
|
118 |
+func (r *V2) Ping() error { |
|
119 |
+ // We always ping through HTTP for our test registry. |
|
120 |
+ resp, err := http.Get(fmt.Sprintf("http://%s/v2/", r.registryURL)) |
|
121 |
+ if err != nil { |
|
122 |
+ return err |
|
123 |
+ } |
|
124 |
+ resp.Body.Close() |
|
125 |
+ |
|
126 |
+ fail := resp.StatusCode != http.StatusOK |
|
127 |
+ if r.auth != "" { |
|
128 |
+ // unauthorized is a _good_ status when pinging v2/ and it needs auth |
|
129 |
+ fail = fail && resp.StatusCode != http.StatusUnauthorized |
|
130 |
+ } |
|
131 |
+ if fail { |
|
132 |
+ return fmt.Errorf("registry ping replied with an unexpected status code %d", resp.StatusCode) |
|
133 |
+ } |
|
134 |
+ return nil |
|
135 |
+} |
|
136 |
+ |
|
137 |
+// Close kills the registry server |
|
138 |
+func (r *V2) Close() { |
|
139 |
+ r.cmd.Process.Kill() |
|
140 |
+ os.RemoveAll(r.dir) |
|
141 |
+} |
|
142 |
+ |
|
143 |
+func (r *V2) getBlobFilename(blobDigest digest.Digest) string { |
|
144 |
+ // Split the digest into its algorithm and hex components. |
|
145 |
+ dgstAlg, dgstHex := blobDigest.Algorithm(), blobDigest.Hex() |
|
146 |
+ |
|
147 |
+ // The path to the target blob data looks something like: |
|
148 |
+ // baseDir + "docker/registry/v2/blobs/sha256/a3/a3ed...46d4/data" |
|
149 |
+ return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", r.dir, dgstAlg, dgstHex[:2], dgstHex) |
|
150 |
+} |
|
151 |
+ |
|
152 |
+// ReadBlobContents read the file corresponding to the specified digest |
|
153 |
+func (r *V2) ReadBlobContents(t testingT, blobDigest digest.Digest) []byte { |
|
154 |
+ // Load the target manifest blob. |
|
155 |
+ manifestBlob, err := ioutil.ReadFile(r.getBlobFilename(blobDigest)) |
|
156 |
+ if err != nil { |
|
157 |
+ t.Fatalf("unable to read blob: %s", err) |
|
158 |
+ } |
|
159 |
+ |
|
160 |
+ return manifestBlob |
|
161 |
+} |
|
162 |
+ |
|
163 |
+// WriteBlobContents write the file corresponding to the specified digest with the given content |
|
164 |
+func (r *V2) WriteBlobContents(t testingT, blobDigest digest.Digest, data []byte) { |
|
165 |
+ if err := ioutil.WriteFile(r.getBlobFilename(blobDigest), data, os.FileMode(0644)); err != nil { |
|
166 |
+ t.Fatalf("unable to write malicious data blob: %s", err) |
|
167 |
+ } |
|
168 |
+} |
|
169 |
+ |
|
170 |
+// TempMoveBlobData moves the existing data file aside, so that we can replace it with a |
|
171 |
+// malicious blob of data for example. |
|
172 |
+func (r *V2) TempMoveBlobData(t testingT, blobDigest digest.Digest) (undo func()) { |
|
173 |
+ tempFile, err := ioutil.TempFile("", "registry-temp-blob-") |
|
174 |
+ if err != nil { |
|
175 |
+ t.Fatalf("unable to get temporary blob file: %s", err) |
|
176 |
+ } |
|
177 |
+ tempFile.Close() |
|
178 |
+ |
|
179 |
+ blobFilename := r.getBlobFilename(blobDigest) |
|
180 |
+ |
|
181 |
+ // Move the existing data file aside, so that we can replace it with a |
|
182 |
+ // another blob of data. |
|
183 |
+ if err := os.Rename(blobFilename, tempFile.Name()); err != nil { |
|
184 |
+ os.Remove(tempFile.Name()) |
|
185 |
+ t.Fatalf("unable to move data blob: %s", err) |
|
186 |
+ } |
|
187 |
+ |
|
188 |
+ return func() { |
|
189 |
+ os.Rename(tempFile.Name(), blobFilename) |
|
190 |
+ os.Remove(tempFile.Name()) |
|
191 |
+ } |
|
192 |
+} |
|
193 |
+ |
|
194 |
+// Username returns the configured user name of the server |
|
195 |
+func (r *V2) Username() string { |
|
196 |
+ return r.username |
|
197 |
+} |
|
198 |
+ |
|
199 |
+// Password returns the configured password of the server |
|
200 |
+func (r *V2) Password() string { |
|
201 |
+ return r.password |
|
202 |
+} |
|
203 |
+ |
|
204 |
+// Path returns the path where the registry write data |
|
205 |
+func (r *V2) Path() string { |
|
206 |
+ return filepath.Join(r.dir, "docker", "registry", "v2") |
|
207 |
+} |
0 | 208 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,61 @@ |
0 |
+package registry |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "net/http" |
|
4 |
+ "net/http/httptest" |
|
5 |
+ "regexp" |
|
6 |
+ "strings" |
|
7 |
+ "sync" |
|
8 |
+) |
|
9 |
+ |
|
10 |
+type handlerFunc func(w http.ResponseWriter, r *http.Request) |
|
11 |
+ |
|
12 |
+// Mock represent a registry mock |
|
13 |
+type Mock struct { |
|
14 |
+ server *httptest.Server |
|
15 |
+ hostport string |
|
16 |
+ handlers map[string]handlerFunc |
|
17 |
+ mu sync.Mutex |
|
18 |
+} |
|
19 |
+ |
|
20 |
+// RegisterHandler register the specified handler for the registry mock |
|
21 |
+func (tr *Mock) RegisterHandler(path string, h handlerFunc) { |
|
22 |
+ tr.mu.Lock() |
|
23 |
+ defer tr.mu.Unlock() |
|
24 |
+ tr.handlers[path] = h |
|
25 |
+} |
|
26 |
+ |
|
27 |
+// NewMock creates a registry mock |
|
28 |
+func NewMock(t testingT) (*Mock, error) { |
|
29 |
+ testReg := &Mock{handlers: make(map[string]handlerFunc)} |
|
30 |
+ |
|
31 |
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
32 |
+ url := r.URL.String() |
|
33 |
+ |
|
34 |
+ var matched bool |
|
35 |
+ var err error |
|
36 |
+ for re, function := range testReg.handlers { |
|
37 |
+ matched, err = regexp.MatchString(re, url) |
|
38 |
+ if err != nil { |
|
39 |
+ t.Fatal("Error with handler regexp") |
|
40 |
+ } |
|
41 |
+ if matched { |
|
42 |
+ function(w, r) |
|
43 |
+ break |
|
44 |
+ } |
|
45 |
+ } |
|
46 |
+ |
|
47 |
+ if !matched { |
|
48 |
+ t.Fatalf("Unable to match %s with regexp", url) |
|
49 |
+ } |
|
50 |
+ })) |
|
51 |
+ |
|
52 |
+ testReg.server = ts |
|
53 |
+ testReg.hostport = strings.Replace(ts.URL, "http://", "", 1) |
|
54 |
+ return testReg, nil |
|
55 |
+} |
|
56 |
+ |
|
57 |
+// URL returns the url of the registry |
|
58 |
+func (tr *Mock) URL() string { |
|
59 |
+ return tr.hostport |
|
60 |
+} |
0 | 61 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,12 @@ |
0 |
+package registry |
|
1 |
+ |
|
2 |
+import "os/exec" |
|
3 |
+ |
|
4 |
+// Hosting returns wether the host can host a registry (v2) or not |
|
5 |
+func Hosting() bool { |
|
6 |
+ // for now registry binary is built only if we're running inside |
|
7 |
+ // container through `make test`. Figure that out by testing if |
|
8 |
+ // registry binary is in PATH. |
|
9 |
+ _, err := exec.LookPath(v2binary) |
|
10 |
+ return err == nil |
|
11 |
+} |
0 | 12 |
deleted file mode 100644 |
... | ... |
@@ -1,55 +0,0 @@ |
1 |
-package main |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "net/http" |
|
5 |
- "net/http/httptest" |
|
6 |
- "regexp" |
|
7 |
- "strings" |
|
8 |
- "sync" |
|
9 |
- |
|
10 |
- "github.com/go-check/check" |
|
11 |
-) |
|
12 |
- |
|
13 |
-type handlerFunc func(w http.ResponseWriter, r *http.Request) |
|
14 |
- |
|
15 |
-type testRegistry struct { |
|
16 |
- server *httptest.Server |
|
17 |
- hostport string |
|
18 |
- handlers map[string]handlerFunc |
|
19 |
- mu sync.Mutex |
|
20 |
-} |
|
21 |
- |
|
22 |
-func (tr *testRegistry) registerHandler(path string, h handlerFunc) { |
|
23 |
- tr.mu.Lock() |
|
24 |
- defer tr.mu.Unlock() |
|
25 |
- tr.handlers[path] = h |
|
26 |
-} |
|
27 |
- |
|
28 |
-func newTestRegistry(c *check.C) (*testRegistry, error) { |
|
29 |
- testReg := &testRegistry{handlers: make(map[string]handlerFunc)} |
|
30 |
- |
|
31 |
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
32 |
- url := r.URL.String() |
|
33 |
- |
|
34 |
- var matched bool |
|
35 |
- var err error |
|
36 |
- for re, function := range testReg.handlers { |
|
37 |
- matched, err = regexp.MatchString(re, url) |
|
38 |
- if err != nil { |
|
39 |
- c.Fatal("Error with handler regexp") |
|
40 |
- } |
|
41 |
- if matched { |
|
42 |
- function(w, r) |
|
43 |
- break |
|
44 |
- } |
|
45 |
- } |
|
46 |
- |
|
47 |
- if !matched { |
|
48 |
- c.Fatalf("Unable to match %s with regexp", url) |
|
49 |
- } |
|
50 |
- })) |
|
51 |
- |
|
52 |
- testReg.server = ts |
|
53 |
- testReg.hostport = strings.Replace(ts.URL, "http://", "", 1) |
|
54 |
- return testReg, nil |
|
55 |
-} |
56 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,177 +0,0 @@ |
1 |
-package main |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "io/ioutil" |
|
6 |
- "net/http" |
|
7 |
- "os" |
|
8 |
- "os/exec" |
|
9 |
- "path/filepath" |
|
10 |
- |
|
11 |
- "github.com/docker/distribution/digest" |
|
12 |
- "github.com/go-check/check" |
|
13 |
-) |
|
14 |
- |
|
15 |
-const ( |
|
16 |
- v2binary = "registry-v2" |
|
17 |
- v2binarySchema1 = "registry-v2-schema1" |
|
18 |
-) |
|
19 |
- |
|
20 |
-type testRegistryV2 struct { |
|
21 |
- cmd *exec.Cmd |
|
22 |
- dir string |
|
23 |
- auth string |
|
24 |
- username string |
|
25 |
- password string |
|
26 |
- email string |
|
27 |
-} |
|
28 |
- |
|
29 |
-func newTestRegistryV2(c *check.C, schema1 bool, auth, tokenURL string) (*testRegistryV2, error) { |
|
30 |
- tmp, err := ioutil.TempDir("", "registry-test-") |
|
31 |
- if err != nil { |
|
32 |
- return nil, err |
|
33 |
- } |
|
34 |
- template := `version: 0.1 |
|
35 |
-loglevel: debug |
|
36 |
-storage: |
|
37 |
- filesystem: |
|
38 |
- rootdirectory: %s |
|
39 |
-http: |
|
40 |
- addr: %s |
|
41 |
-%s` |
|
42 |
- var ( |
|
43 |
- authTemplate string |
|
44 |
- username string |
|
45 |
- password string |
|
46 |
- email string |
|
47 |
- ) |
|
48 |
- switch auth { |
|
49 |
- case "htpasswd": |
|
50 |
- htpasswdPath := filepath.Join(tmp, "htpasswd") |
|
51 |
- // generated with: htpasswd -Bbn testuser testpassword |
|
52 |
- userpasswd := "testuser:$2y$05$sBsSqk0OpSD1uTZkHXc4FeJ0Z70wLQdAX/82UiHuQOKbNbBrzs63m" |
|
53 |
- username = "testuser" |
|
54 |
- password = "testpassword" |
|
55 |
- email = "test@test.org" |
|
56 |
- if err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644)); err != nil { |
|
57 |
- return nil, err |
|
58 |
- } |
|
59 |
- authTemplate = fmt.Sprintf(`auth: |
|
60 |
- htpasswd: |
|
61 |
- realm: basic-realm |
|
62 |
- path: %s |
|
63 |
-`, htpasswdPath) |
|
64 |
- case "token": |
|
65 |
- authTemplate = fmt.Sprintf(`auth: |
|
66 |
- token: |
|
67 |
- realm: %s |
|
68 |
- service: "registry" |
|
69 |
- issuer: "auth-registry" |
|
70 |
- rootcertbundle: "fixtures/registry/cert.pem" |
|
71 |
-`, tokenURL) |
|
72 |
- } |
|
73 |
- |
|
74 |
- confPath := filepath.Join(tmp, "config.yaml") |
|
75 |
- config, err := os.Create(confPath) |
|
76 |
- if err != nil { |
|
77 |
- return nil, err |
|
78 |
- } |
|
79 |
- defer config.Close() |
|
80 |
- |
|
81 |
- if _, err := fmt.Fprintf(config, template, tmp, privateRegistryURL, authTemplate); err != nil { |
|
82 |
- os.RemoveAll(tmp) |
|
83 |
- return nil, err |
|
84 |
- } |
|
85 |
- |
|
86 |
- binary := v2binary |
|
87 |
- if schema1 { |
|
88 |
- binary = v2binarySchema1 |
|
89 |
- } |
|
90 |
- cmd := exec.Command(binary, confPath) |
|
91 |
- if err := cmd.Start(); err != nil { |
|
92 |
- os.RemoveAll(tmp) |
|
93 |
- if os.IsNotExist(err) { |
|
94 |
- c.Skip(err.Error()) |
|
95 |
- } |
|
96 |
- return nil, err |
|
97 |
- } |
|
98 |
- return &testRegistryV2{ |
|
99 |
- cmd: cmd, |
|
100 |
- dir: tmp, |
|
101 |
- auth: auth, |
|
102 |
- username: username, |
|
103 |
- password: password, |
|
104 |
- email: email, |
|
105 |
- }, nil |
|
106 |
-} |
|
107 |
- |
|
108 |
-func (t *testRegistryV2) Ping() error { |
|
109 |
- // We always ping through HTTP for our test registry. |
|
110 |
- resp, err := http.Get(fmt.Sprintf("http://%s/v2/", privateRegistryURL)) |
|
111 |
- if err != nil { |
|
112 |
- return err |
|
113 |
- } |
|
114 |
- resp.Body.Close() |
|
115 |
- |
|
116 |
- fail := resp.StatusCode != http.StatusOK |
|
117 |
- if t.auth != "" { |
|
118 |
- // unauthorized is a _good_ status when pinging v2/ and it needs auth |
|
119 |
- fail = fail && resp.StatusCode != http.StatusUnauthorized |
|
120 |
- } |
|
121 |
- if fail { |
|
122 |
- return fmt.Errorf("registry ping replied with an unexpected status code %d", resp.StatusCode) |
|
123 |
- } |
|
124 |
- return nil |
|
125 |
-} |
|
126 |
- |
|
127 |
-func (t *testRegistryV2) Close() { |
|
128 |
- t.cmd.Process.Kill() |
|
129 |
- os.RemoveAll(t.dir) |
|
130 |
-} |
|
131 |
- |
|
132 |
-func (t *testRegistryV2) getBlobFilename(blobDigest digest.Digest) string { |
|
133 |
- // Split the digest into its algorithm and hex components. |
|
134 |
- dgstAlg, dgstHex := blobDigest.Algorithm(), blobDigest.Hex() |
|
135 |
- |
|
136 |
- // The path to the target blob data looks something like: |
|
137 |
- // baseDir + "docker/registry/v2/blobs/sha256/a3/a3ed...46d4/data" |
|
138 |
- return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", t.dir, dgstAlg, dgstHex[:2], dgstHex) |
|
139 |
-} |
|
140 |
- |
|
141 |
-func (t *testRegistryV2) readBlobContents(c *check.C, blobDigest digest.Digest) []byte { |
|
142 |
- // Load the target manifest blob. |
|
143 |
- manifestBlob, err := ioutil.ReadFile(t.getBlobFilename(blobDigest)) |
|
144 |
- if err != nil { |
|
145 |
- c.Fatalf("unable to read blob: %s", err) |
|
146 |
- } |
|
147 |
- |
|
148 |
- return manifestBlob |
|
149 |
-} |
|
150 |
- |
|
151 |
-func (t *testRegistryV2) writeBlobContents(c *check.C, blobDigest digest.Digest, data []byte) { |
|
152 |
- if err := ioutil.WriteFile(t.getBlobFilename(blobDigest), data, os.FileMode(0644)); err != nil { |
|
153 |
- c.Fatalf("unable to write malicious data blob: %s", err) |
|
154 |
- } |
|
155 |
-} |
|
156 |
- |
|
157 |
-func (t *testRegistryV2) tempMoveBlobData(c *check.C, blobDigest digest.Digest) (undo func()) { |
|
158 |
- tempFile, err := ioutil.TempFile("", "registry-temp-blob-") |
|
159 |
- if err != nil { |
|
160 |
- c.Fatalf("unable to get temporary blob file: %s", err) |
|
161 |
- } |
|
162 |
- tempFile.Close() |
|
163 |
- |
|
164 |
- blobFilename := t.getBlobFilename(blobDigest) |
|
165 |
- |
|
166 |
- // Move the existing data file aside, so that we can replace it with a |
|
167 |
- // another blob of data. |
|
168 |
- if err := os.Rename(blobFilename, tempFile.Name()); err != nil { |
|
169 |
- os.Remove(tempFile.Name()) |
|
170 |
- c.Fatalf("unable to move data blob: %s", err) |
|
171 |
- } |
|
172 |
- |
|
173 |
- return func() { |
|
174 |
- os.Rename(tempFile.Name(), blobFilename) |
|
175 |
- os.Remove(tempFile.Name()) |
|
176 |
- } |
|
177 |
-} |
... | ... |
@@ -105,14 +105,6 @@ func Apparmor() bool { |
105 | 105 |
return err == nil && len(buf) > 1 && buf[0] == 'Y' |
106 | 106 |
} |
107 | 107 |
|
108 |
-func RegistryHosting() bool { |
|
109 |
- // for now registry binary is built only if we're running inside |
|
110 |
- // container through `make test`. Figure that out by testing if |
|
111 |
- // registry binary is in PATH. |
|
112 |
- _, err := exec.LookPath(v2binary) |
|
113 |
- return err == nil |
|
114 |
-} |
|
115 |
- |
|
116 | 108 |
func NotaryHosting() bool { |
117 | 109 |
// for now notary binary is built only if we're running inside |
118 | 110 |
// container through `make test`. Figure that out by testing if |