From 4300e5e8818571a55e00d9987bec3ad6ca92dc6f Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Fri, 30 Dec 2016 19:10:04 +0100 Subject: [PATCH] Add a registry package with registry v1/v2 code This extract what was in registry_test.go and registry_mock_test.go. This also move `RegistryHosting` requirement to `registry.Hosting` Signed-off-by: Vincent Demeester --- integration-cli/check_test.go | 23 ++-- integration-cli/docker_cli_build_test.go | 4 +- integration-cli/docker_cli_by_digest_test.go | 24 ++-- integration-cli/docker_cli_login_test.go | 4 +- integration-cli/docker_cli_logout_test.go | 6 +- integration-cli/docker_cli_pull_local_test.go | 8 +- .../docker_cli_registry_user_agent_test.go | 29 ++--- integration-cli/docker_cli_v2_only_test.go | 35 +++--- integration-cli/docker_utils_test.go | 5 +- .../registry.go} | 109 +++++++++++------- .../registry_mock.go} | 24 ++-- integration-cli/registry/requirement.go | 12 ++ integration-cli/requirements_test.go | 8 -- 13 files changed, 168 insertions(+), 123 deletions(-) rename integration-cli/{registry_test.go => registry/registry.go} (54%) rename integration-cli/{registry_mock_test.go => registry/registry_mock.go} (59%) create mode 100644 integration-cli/registry/requirement.go diff --git a/integration-cli/check_test.go b/integration-cli/check_test.go index d160df5511..3a80943916 100644 --- a/integration-cli/check_test.go +++ b/integration-cli/check_test.go @@ -16,6 +16,7 @@ import ( cliconfig "github.com/docker/docker/cli/config" "github.com/docker/docker/integration-cli/daemon" "github.com/docker/docker/integration-cli/environment" + "github.com/docker/docker/integration-cli/registry" "github.com/docker/docker/pkg/reexec" "github.com/go-check/check" ) @@ -172,7 +173,7 @@ func init() { type DockerRegistrySuite struct { ds *DockerSuite - reg *testRegistryV2 + reg *registry.V2 d *daemon.Daemon } @@ -181,7 +182,7 @@ func (s *DockerRegistrySuite) OnTimeout(c *check.C) { } func (s *DockerRegistrySuite) SetUpTest(c *check.C) { - testRequires(c, DaemonIsLinux, RegistryHosting) + testRequires(c, DaemonIsLinux, registry.Hosting) s.reg = setupRegistry(c, false, "", "") s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ Experimental: experimentalDaemon, @@ -206,7 +207,7 @@ func init() { type DockerSchema1RegistrySuite struct { ds *DockerSuite - reg *testRegistryV2 + reg *registry.V2 d *daemon.Daemon } @@ -215,7 +216,7 @@ func (s *DockerSchema1RegistrySuite) OnTimeout(c *check.C) { } func (s *DockerSchema1RegistrySuite) SetUpTest(c *check.C) { - testRequires(c, DaemonIsLinux, RegistryHosting, NotArm64) + testRequires(c, DaemonIsLinux, registry.Hosting, NotArm64) s.reg = setupRegistry(c, true, "", "") s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ Experimental: experimentalDaemon, @@ -240,7 +241,7 @@ func init() { type DockerRegistryAuthHtpasswdSuite struct { ds *DockerSuite - reg *testRegistryV2 + reg *registry.V2 d *daemon.Daemon } @@ -249,7 +250,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) OnTimeout(c *check.C) { } func (s *DockerRegistryAuthHtpasswdSuite) SetUpTest(c *check.C) { - testRequires(c, DaemonIsLinux, RegistryHosting) + testRequires(c, DaemonIsLinux, registry.Hosting) s.reg = setupRegistry(c, false, "htpasswd", "") s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ Experimental: experimentalDaemon, @@ -276,7 +277,7 @@ func init() { type DockerRegistryAuthTokenSuite struct { ds *DockerSuite - reg *testRegistryV2 + reg *registry.V2 d *daemon.Daemon } @@ -285,7 +286,7 @@ func (s *DockerRegistryAuthTokenSuite) OnTimeout(c *check.C) { } func (s *DockerRegistryAuthTokenSuite) SetUpTest(c *check.C) { - testRequires(c, DaemonIsLinux, RegistryHosting) + testRequires(c, DaemonIsLinux, registry.Hosting) s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ Experimental: experimentalDaemon, }) @@ -449,12 +450,12 @@ func init() { type DockerTrustSuite struct { ds *DockerSuite - reg *testRegistryV2 + reg *registry.V2 not *testNotary } func (s *DockerTrustSuite) SetUpTest(c *check.C) { - testRequires(c, RegistryHosting, NotaryServerHosting) + testRequires(c, registry.Hosting, NotaryServerHosting) s.reg = setupRegistry(c, false, "", "") s.not = setupNotary(c) } @@ -487,7 +488,7 @@ func init() { type DockerTrustedSwarmSuite struct { swarmSuite DockerSwarmSuite trustSuite DockerTrustSuite - reg *testRegistryV2 + reg *registry.V2 not *testNotary } diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index 2c66f0e9d2..211af51e52 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -6580,7 +6580,7 @@ func (s *DockerSuite) TestBuildLabelOverwrite(c *check.C) { } func (s *DockerRegistryAuthHtpasswdSuite) TestBuildFromAuthenticatedRegistry(c *check.C) { - dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) + dockerCmd(c, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) baseImage := privateRegistryURL + "/baseimage" @@ -6625,7 +6625,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestBuildWithExternalAuth(c *check.C) err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) c.Assert(err, checker.IsNil) - dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) + dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) b, err := ioutil.ReadFile(configPath) c.Assert(err, checker.IsNil) diff --git a/integration-cli/docker_cli_by_digest_test.go b/integration-cli/docker_cli_by_digest_test.go index c28ffaca98..e8f3dd9764 100644 --- a/integration-cli/docker_cli_by_digest_test.go +++ b/integration-cli/docker_cli_by_digest_test.go @@ -533,7 +533,7 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) { c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) // Load the target manifest blob. - manifestBlob := s.reg.readBlobContents(c, manifestDigest) + manifestBlob := s.reg.ReadBlobContents(c, manifestDigest) var imgManifest schema2.Manifest err = json.Unmarshal(manifestBlob, &imgManifest) @@ -544,13 +544,13 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) { // Move the existing data file aside, so that we can replace it with a // malicious blob of data. NOTE: we defer the returned undo func. - undo := s.reg.tempMoveBlobData(c, manifestDigest) + undo := s.reg.TempMoveBlobData(c, manifestDigest) defer undo() alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ") c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON")) - s.reg.writeBlobContents(c, manifestDigest, alteredManifestBlob) + s.reg.WriteBlobContents(c, manifestDigest, alteredManifestBlob) // Now try pulling that image by digest. We should get an error about // digest verification for the manifest digest. @@ -573,7 +573,7 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) // Load the target manifest blob. - manifestBlob := s.reg.readBlobContents(c, manifestDigest) + manifestBlob := s.reg.ReadBlobContents(c, manifestDigest) var imgManifest schema1.Manifest err = json.Unmarshal(manifestBlob, &imgManifest) @@ -586,13 +586,13 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C // Move the existing data file aside, so that we can replace it with a // malicious blob of data. NOTE: we defer the returned undo func. - undo := s.reg.tempMoveBlobData(c, manifestDigest) + undo := s.reg.TempMoveBlobData(c, manifestDigest) defer undo() alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ") c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON")) - s.reg.writeBlobContents(c, manifestDigest, alteredManifestBlob) + s.reg.WriteBlobContents(c, manifestDigest, alteredManifestBlob) // Now try pulling that image by digest. We should get an error about // digest verification for the manifest digest. @@ -615,7 +615,7 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { c.Assert(err, checker.IsNil) // Load the target manifest blob. - manifestBlob := s.reg.readBlobContents(c, manifestDigest) + manifestBlob := s.reg.ReadBlobContents(c, manifestDigest) var imgManifest schema2.Manifest err = json.Unmarshal(manifestBlob, &imgManifest) @@ -626,11 +626,11 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { // Move the existing data file aside, so that we can replace it with a // malicious blob of data. NOTE: we defer the returned undo func. - undo := s.reg.tempMoveBlobData(c, targetLayerDigest) + undo := s.reg.TempMoveBlobData(c, targetLayerDigest) defer undo() // Now make a fake data blob in this directory. - s.reg.writeBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) + s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) // Now try pulling that image by digest. We should get an error about // digest verification for the target layer digest. @@ -658,7 +658,7 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { c.Assert(err, checker.IsNil) // Load the target manifest blob. - manifestBlob := s.reg.readBlobContents(c, manifestDigest) + manifestBlob := s.reg.ReadBlobContents(c, manifestDigest) var imgManifest schema1.Manifest err = json.Unmarshal(manifestBlob, &imgManifest) @@ -669,11 +669,11 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { // Move the existing data file aside, so that we can replace it with a // malicious blob of data. NOTE: we defer the returned undo func. - undo := s.reg.tempMoveBlobData(c, targetLayerDigest) + undo := s.reg.TempMoveBlobData(c, targetLayerDigest) defer undo() // Now make a fake data blob in this directory. - s.reg.writeBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) + s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) // Now try pulling that image by digest. We should get an error about // digest verification for the target layer digest. diff --git a/integration-cli/docker_cli_login_test.go b/integration-cli/docker_cli_login_test.go index 9cf5f2f37a..82fcf778e5 100644 --- a/integration-cli/docker_cli_login_test.go +++ b/integration-cli/docker_cli_login_test.go @@ -21,10 +21,10 @@ func (s *DockerSuite) TestLoginWithoutTTY(c *check.C) { func (s *DockerRegistryAuthHtpasswdSuite) TestLoginToPrivateRegistry(c *check.C) { // wrong credentials - out, _, err := dockerCmdWithError("login", "-u", s.reg.username, "-p", "WRONGPASSWORD", privateRegistryURL) + out, _, err := dockerCmdWithError("login", "-u", s.reg.Username(), "-p", "WRONGPASSWORD", privateRegistryURL) c.Assert(err, checker.NotNil, check.Commentf(out)) c.Assert(out, checker.Contains, "401 Unauthorized") // now it's fine - dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) + dockerCmd(c, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) } diff --git a/integration-cli/docker_cli_logout_test.go b/integration-cli/docker_cli_logout_test.go index a5f4b108cf..31ce774d76 100644 --- a/integration-cli/docker_cli_logout_test.go +++ b/integration-cli/docker_cli_logout_test.go @@ -35,7 +35,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithExternalAuth(c *check.C) err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) c.Assert(err, checker.IsNil) - dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) + dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) b, err := ioutil.ReadFile(configPath) c.Assert(err, checker.IsNil) @@ -71,7 +71,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithWrongHostnamesStored(c * os.Setenv("PATH", testPath) cmd := exec.Command("docker-credential-shell-test", "store") - stdin := bytes.NewReader([]byte(fmt.Sprintf(`{"ServerURL": "https://%s", "Username": "%s", "Secret": "%s"}`, privateRegistryURL, s.reg.username, s.reg.password))) + stdin := bytes.NewReader([]byte(fmt.Sprintf(`{"ServerURL": "https://%s", "Username": "%s", "Secret": "%s"}`, privateRegistryURL, s.reg.Username(), s.reg.Password()))) cmd.Stdin = stdin c.Assert(cmd.Run(), checker.IsNil) @@ -84,7 +84,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithWrongHostnamesStored(c * err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) c.Assert(err, checker.IsNil) - dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) + dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) b, err := ioutil.ReadFile(configPath) c.Assert(err, checker.IsNil) diff --git a/integration-cli/docker_cli_pull_local_test.go b/integration-cli/docker_cli_pull_local_test.go index cb14c2c702..7d3f62ee0c 100644 --- a/integration-cli/docker_cli_pull_local_test.go +++ b/integration-cli/docker_cli_pull_local_test.go @@ -347,7 +347,7 @@ func (s *DockerRegistrySuite) TestPullManifestList(c *check.C) { manifestListDigest := digest.FromBytes(manifestListJSON) hexDigest := manifestListDigest.Hex() - registryV2Path := filepath.Join(s.reg.dir, "docker", "registry", "v2") + registryV2Path := s.reg.Path() // Write manifest list to blob store blobDir := filepath.Join(registryV2Path, "blobs", "sha256", hexDigest[:2], hexDigest) @@ -411,7 +411,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuthLoginWithSchem err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) c.Assert(err, checker.IsNil) - dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) + dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) b, err := ioutil.ReadFile(configPath) c.Assert(err, checker.IsNil) @@ -421,7 +421,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuthLoginWithSchem dockerCmd(c, "--config", tmp, "push", repoName) dockerCmd(c, "--config", tmp, "logout", privateRegistryURL) - dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, "https://"+privateRegistryURL) + dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), "https://"+privateRegistryURL) dockerCmd(c, "--config", tmp, "pull", repoName) // likewise push should work @@ -456,7 +456,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuth(c *check.C) { err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644) c.Assert(err, checker.IsNil) - dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL) + dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL) b, err := ioutil.ReadFile(configPath) c.Assert(err, checker.IsNil) diff --git a/integration-cli/docker_cli_registry_user_agent_test.go b/integration-cli/docker_cli_registry_user_agent_test.go index 4db3b33acc..7d1989e2b3 100644 --- a/integration-cli/docker_cli_registry_user_agent_test.go +++ b/integration-cli/docker_cli_registry_user_agent_test.go @@ -5,6 +5,7 @@ import ( "net/http" "regexp" + "github.com/docker/docker/integration-cli/registry" "github.com/go-check/check" ) @@ -46,8 +47,8 @@ func regexpCheckUA(c *check.C, ua string) { c.Assert(bMatchUpstreamUA, check.Equals, true, check.Commentf("(Upstream) Docker Client User-Agent malformed")) } -func registerUserAgentHandler(reg *testRegistry, result *string) { - reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { +func registerUserAgentHandler(reg *registry.Mock, result *string) { + reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) var ua string for k, v := range r.Header { @@ -70,30 +71,30 @@ func (s *DockerRegistrySuite) TestUserAgentPassThrough(c *check.C) { loginUA string ) - buildReg, err := newTestRegistry(c) + buildReg, err := registry.NewMock(c) c.Assert(err, check.IsNil) registerUserAgentHandler(buildReg, &buildUA) - buildRepoName := fmt.Sprintf("%s/busybox", buildReg.hostport) + buildRepoName := fmt.Sprintf("%s/busybox", buildReg.URL()) - pullReg, err := newTestRegistry(c) + pullReg, err := registry.NewMock(c) c.Assert(err, check.IsNil) registerUserAgentHandler(pullReg, &pullUA) - pullRepoName := fmt.Sprintf("%s/busybox", pullReg.hostport) + pullRepoName := fmt.Sprintf("%s/busybox", pullReg.URL()) - pushReg, err := newTestRegistry(c) + pushReg, err := registry.NewMock(c) c.Assert(err, check.IsNil) registerUserAgentHandler(pushReg, &pushUA) - pushRepoName := fmt.Sprintf("%s/busybox", pushReg.hostport) + pushRepoName := fmt.Sprintf("%s/busybox", pushReg.URL()) - loginReg, err := newTestRegistry(c) + loginReg, err := registry.NewMock(c) c.Assert(err, check.IsNil) registerUserAgentHandler(loginReg, &loginUA) s.d.Start(c, - "--insecure-registry", buildReg.hostport, - "--insecure-registry", pullReg.hostport, - "--insecure-registry", pushReg.hostport, - "--insecure-registry", loginReg.hostport, + "--insecure-registry", buildReg.URL(), + "--insecure-registry", pullReg.URL(), + "--insecure-registry", pushReg.URL(), + "--insecure-registry", loginReg.URL(), "--disable-legacy-registry=true") dockerfileName, cleanup1, err := makefile(fmt.Sprintf("FROM %s", buildRepoName)) @@ -102,7 +103,7 @@ func (s *DockerRegistrySuite) TestUserAgentPassThrough(c *check.C) { s.d.Cmd("build", "--file", dockerfileName, ".") regexpCheckUA(c, buildUA) - s.d.Cmd("login", "-u", "richard", "-p", "testtest", loginReg.hostport) + s.d.Cmd("login", "-u", "richard", "-p", "testtest", loginReg.URL()) regexpCheckUA(c, loginUA) s.d.Cmd("pull", pullRepoName) diff --git a/integration-cli/docker_cli_v2_only_test.go b/integration-cli/docker_cli_v2_only_test.go index 228d77c4cb..6e0d944590 100644 --- a/integration-cli/docker_cli_v2_only_test.go +++ b/integration-cli/docker_cli_v2_only_test.go @@ -6,6 +6,7 @@ import ( "net/http" "os" + "github.com/docker/docker/integration-cli/registry" "github.com/go-check/check" ) @@ -36,29 +37,29 @@ func makefile(contents string) (string, func(), error) { // TestV2Only ensures that a daemon in v2-only mode does not // attempt to contact any v1 registry endpoints. func (s *DockerRegistrySuite) TestV2Only(c *check.C) { - reg, err := newTestRegistry(c) + reg, err := registry.NewMock(c) c.Assert(err, check.IsNil) - reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { + reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) }) - reg.registerHandler("/v1/.*", func(w http.ResponseWriter, r *http.Request) { + reg.RegisterHandler("/v1/.*", func(w http.ResponseWriter, r *http.Request) { c.Fatal("V1 registry contacted") }) - repoName := fmt.Sprintf("%s/busybox", reg.hostport) + repoName := fmt.Sprintf("%s/busybox", reg.URL()) - s.d.Start(c, "--insecure-registry", reg.hostport, "--disable-legacy-registry=true") + s.d.Start(c, "--insecure-registry", reg.URL(), "--disable-legacy-registry=true") - dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport)) + dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.URL())) c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile")) defer cleanup() s.d.Cmd("build", "--file", dockerfileName, ".") s.d.Cmd("run", repoName) - s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.hostport) + s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.URL()) s.d.Cmd("tag", "busybox", repoName) s.d.Cmd("push", repoName) s.d.Cmd("pull", repoName) @@ -68,49 +69,49 @@ func (s *DockerRegistrySuite) TestV2Only(c *check.C) { // and ensure v1 endpoints are hit for the following operations: // login, push, pull, build & run func (s *DockerRegistrySuite) TestV1(c *check.C) { - reg, err := newTestRegistry(c) + reg, err := registry.NewMock(c) c.Assert(err, check.IsNil) v2Pings := 0 - reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { + reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) { v2Pings++ // V2 ping 404 causes fallback to v1 w.WriteHeader(404) }) v1Pings := 0 - reg.registerHandler("/v1/_ping", func(w http.ResponseWriter, r *http.Request) { + reg.RegisterHandler("/v1/_ping", func(w http.ResponseWriter, r *http.Request) { v1Pings++ }) v1Logins := 0 - reg.registerHandler("/v1/users/", func(w http.ResponseWriter, r *http.Request) { + reg.RegisterHandler("/v1/users/", func(w http.ResponseWriter, r *http.Request) { v1Logins++ }) v1Repo := 0 - reg.registerHandler("/v1/repositories/busybox/", func(w http.ResponseWriter, r *http.Request) { + reg.RegisterHandler("/v1/repositories/busybox/", func(w http.ResponseWriter, r *http.Request) { v1Repo++ }) - reg.registerHandler("/v1/repositories/busybox/images", func(w http.ResponseWriter, r *http.Request) { + reg.RegisterHandler("/v1/repositories/busybox/images", func(w http.ResponseWriter, r *http.Request) { v1Repo++ }) - s.d.Start(c, "--insecure-registry", reg.hostport, "--disable-legacy-registry=false") + s.d.Start(c, "--insecure-registry", reg.URL(), "--disable-legacy-registry=false") - dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport)) + dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.URL())) c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile")) defer cleanup() s.d.Cmd("build", "--file", dockerfileName, ".") c.Assert(v1Repo, check.Equals, 1, check.Commentf("Expected v1 repository access after build")) - repoName := fmt.Sprintf("%s/busybox", reg.hostport) + repoName := fmt.Sprintf("%s/busybox", reg.URL()) s.d.Cmd("run", repoName) c.Assert(v1Repo, check.Equals, 2, check.Commentf("Expected v1 repository access after run")) - s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.hostport) + s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.URL()) c.Assert(v1Logins, check.Equals, 1, check.Commentf("Expected v1 login attempt")) s.d.Cmd("tag", "busybox", repoName) diff --git a/integration-cli/docker_utils_test.go b/integration-cli/docker_utils_test.go index 90939dc7ce..c2883e8c72 100644 --- a/integration-cli/docker_utils_test.go +++ b/integration-cli/docker_utils_test.go @@ -24,6 +24,7 @@ import ( "github.com/docker/docker/api/types" volumetypes "github.com/docker/docker/api/types/volume" "github.com/docker/docker/integration-cli/daemon" + "github.com/docker/docker/integration-cli/registry" "github.com/docker/docker/opts" "github.com/docker/docker/pkg/integration" "github.com/docker/docker/pkg/integration/checker" @@ -1083,8 +1084,8 @@ func parseEventTime(t time.Time) string { return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())) } -func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *testRegistryV2 { - reg, err := newTestRegistryV2(c, schema1, auth, tokenURL) +func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *registry.V2 { + reg, err := registry.NewV2(schema1, auth, tokenURL, privateRegistryURL) c.Assert(err, check.IsNil) // Wait for registry to be ready to serve requests. diff --git a/integration-cli/registry_test.go b/integration-cli/registry/registry.go similarity index 54% rename from integration-cli/registry_test.go rename to integration-cli/registry/registry.go index 5181570af5..4062734c5c 100644 --- a/integration-cli/registry_test.go +++ b/integration-cli/registry/registry.go @@ -1,4 +1,4 @@ -package main +package registry import ( "fmt" @@ -9,7 +9,6 @@ import ( "path/filepath" "github.com/docker/distribution/digest" - "github.com/go-check/check" ) const ( @@ -17,16 +16,29 @@ const ( v2binarySchema1 = "registry-v2-schema1" ) -type testRegistryV2 struct { - cmd *exec.Cmd - dir string - auth string - username string - password string - email string +type testingT interface { + logT + Fatal(...interface{}) + Fatalf(string, ...interface{}) } -func newTestRegistryV2(c *check.C, schema1 bool, auth, tokenURL string) (*testRegistryV2, error) { +type logT interface { + Logf(string, ...interface{}) +} + +// V2 represent a registry version 2 +type V2 struct { + cmd *exec.Cmd + registryURL string + dir string + auth string + username string + password string + email string +} + +// NewV2 creates a v2 registry server +func NewV2(schema1 bool, auth, tokenURL, registryURL string) (*V2, error) { tmp, err := ioutil.TempDir("", "registry-test-") if err != nil { return nil, err @@ -78,7 +90,7 @@ http: } defer config.Close() - if _, err := fmt.Fprintf(config, template, tmp, privateRegistryURL, authTemplate); err != nil { + if _, err := fmt.Fprintf(config, template, tmp, registryURL, authTemplate); err != nil { os.RemoveAll(tmp) return nil, err } @@ -90,31 +102,30 @@ http: cmd := exec.Command(binary, confPath) if err := cmd.Start(); err != nil { os.RemoveAll(tmp) - if os.IsNotExist(err) { - c.Skip(err.Error()) - } return nil, err } - return &testRegistryV2{ - cmd: cmd, - dir: tmp, - auth: auth, - username: username, - password: password, - email: email, + return &V2{ + cmd: cmd, + dir: tmp, + auth: auth, + username: username, + password: password, + email: email, + registryURL: registryURL, }, nil } -func (t *testRegistryV2) Ping() error { +// Ping sends an http request to the current registry, and fail if it doesn't respond correctly +func (r *V2) Ping() error { // We always ping through HTTP for our test registry. - resp, err := http.Get(fmt.Sprintf("http://%s/v2/", privateRegistryURL)) + resp, err := http.Get(fmt.Sprintf("http://%s/v2/", r.registryURL)) if err != nil { return err } resp.Body.Close() fail := resp.StatusCode != http.StatusOK - if t.auth != "" { + if r.auth != "" { // unauthorized is a _good_ status when pinging v2/ and it needs auth fail = fail && resp.StatusCode != http.StatusUnauthorized } @@ -124,50 +135,55 @@ func (t *testRegistryV2) Ping() error { return nil } -func (t *testRegistryV2) Close() { - t.cmd.Process.Kill() - os.RemoveAll(t.dir) +// Close kills the registry server +func (r *V2) Close() { + r.cmd.Process.Kill() + os.RemoveAll(r.dir) } -func (t *testRegistryV2) getBlobFilename(blobDigest digest.Digest) string { +func (r *V2) getBlobFilename(blobDigest digest.Digest) string { // Split the digest into its algorithm and hex components. dgstAlg, dgstHex := blobDigest.Algorithm(), blobDigest.Hex() // The path to the target blob data looks something like: // baseDir + "docker/registry/v2/blobs/sha256/a3/a3ed...46d4/data" - return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", t.dir, dgstAlg, dgstHex[:2], dgstHex) + return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", r.dir, dgstAlg, dgstHex[:2], dgstHex) } -func (t *testRegistryV2) readBlobContents(c *check.C, blobDigest digest.Digest) []byte { +// ReadBlobContents read the file corresponding to the specified digest +func (r *V2) ReadBlobContents(t testingT, blobDigest digest.Digest) []byte { // Load the target manifest blob. - manifestBlob, err := ioutil.ReadFile(t.getBlobFilename(blobDigest)) + manifestBlob, err := ioutil.ReadFile(r.getBlobFilename(blobDigest)) if err != nil { - c.Fatalf("unable to read blob: %s", err) + t.Fatalf("unable to read blob: %s", err) } return manifestBlob } -func (t *testRegistryV2) writeBlobContents(c *check.C, blobDigest digest.Digest, data []byte) { - if err := ioutil.WriteFile(t.getBlobFilename(blobDigest), data, os.FileMode(0644)); err != nil { - c.Fatalf("unable to write malicious data blob: %s", err) +// WriteBlobContents write the file corresponding to the specified digest with the given content +func (r *V2) WriteBlobContents(t testingT, blobDigest digest.Digest, data []byte) { + if err := ioutil.WriteFile(r.getBlobFilename(blobDigest), data, os.FileMode(0644)); err != nil { + t.Fatalf("unable to write malicious data blob: %s", err) } } -func (t *testRegistryV2) tempMoveBlobData(c *check.C, blobDigest digest.Digest) (undo func()) { +// TempMoveBlobData moves the existing data file aside, so that we can replace it with a +// malicious blob of data for example. +func (r *V2) TempMoveBlobData(t testingT, blobDigest digest.Digest) (undo func()) { tempFile, err := ioutil.TempFile("", "registry-temp-blob-") if err != nil { - c.Fatalf("unable to get temporary blob file: %s", err) + t.Fatalf("unable to get temporary blob file: %s", err) } tempFile.Close() - blobFilename := t.getBlobFilename(blobDigest) + blobFilename := r.getBlobFilename(blobDigest) // Move the existing data file aside, so that we can replace it with a // another blob of data. if err := os.Rename(blobFilename, tempFile.Name()); err != nil { os.Remove(tempFile.Name()) - c.Fatalf("unable to move data blob: %s", err) + t.Fatalf("unable to move data blob: %s", err) } return func() { @@ -175,3 +191,18 @@ func (t *testRegistryV2) tempMoveBlobData(c *check.C, blobDigest digest.Digest) os.Remove(tempFile.Name()) } } + +// Username returns the configured user name of the server +func (r *V2) Username() string { + return r.username +} + +// Password returns the configured password of the server +func (r *V2) Password() string { + return r.password +} + +// Path returns the path where the registry write data +func (r *V2) Path() string { + return filepath.Join(r.dir, "docker", "registry", "v2") +} diff --git a/integration-cli/registry_mock_test.go b/integration-cli/registry/registry_mock.go similarity index 59% rename from integration-cli/registry_mock_test.go rename to integration-cli/registry/registry_mock.go index 300bf46425..5d1980f81c 100644 --- a/integration-cli/registry_mock_test.go +++ b/integration-cli/registry/registry_mock.go @@ -1,4 +1,4 @@ -package main +package registry import ( "net/http" @@ -6,27 +6,28 @@ import ( "regexp" "strings" "sync" - - "github.com/go-check/check" ) type handlerFunc func(w http.ResponseWriter, r *http.Request) -type testRegistry struct { +// Mock represent a registry mock +type Mock struct { server *httptest.Server hostport string handlers map[string]handlerFunc mu sync.Mutex } -func (tr *testRegistry) registerHandler(path string, h handlerFunc) { +// RegisterHandler register the specified handler for the registry mock +func (tr *Mock) RegisterHandler(path string, h handlerFunc) { tr.mu.Lock() defer tr.mu.Unlock() tr.handlers[path] = h } -func newTestRegistry(c *check.C) (*testRegistry, error) { - testReg := &testRegistry{handlers: make(map[string]handlerFunc)} +// NewMock creates a registry mock +func NewMock(t testingT) (*Mock, error) { + testReg := &Mock{handlers: make(map[string]handlerFunc)} ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { url := r.URL.String() @@ -36,7 +37,7 @@ func newTestRegistry(c *check.C) (*testRegistry, error) { for re, function := range testReg.handlers { matched, err = regexp.MatchString(re, url) if err != nil { - c.Fatal("Error with handler regexp") + t.Fatal("Error with handler regexp") } if matched { function(w, r) @@ -45,7 +46,7 @@ func newTestRegistry(c *check.C) (*testRegistry, error) { } if !matched { - c.Fatalf("Unable to match %s with regexp", url) + t.Fatalf("Unable to match %s with regexp", url) } })) @@ -53,3 +54,8 @@ func newTestRegistry(c *check.C) (*testRegistry, error) { testReg.hostport = strings.Replace(ts.URL, "http://", "", 1) return testReg, nil } + +// URL returns the url of the registry +func (tr *Mock) URL() string { + return tr.hostport +} diff --git a/integration-cli/registry/requirement.go b/integration-cli/registry/requirement.go new file mode 100644 index 0000000000..cde48da47c --- /dev/null +++ b/integration-cli/registry/requirement.go @@ -0,0 +1,12 @@ +package registry + +import "os/exec" + +// Hosting returns wether the host can host a registry (v2) or not +func Hosting() bool { + // for now registry binary is built only if we're running inside + // container through `make test`. Figure that out by testing if + // registry binary is in PATH. + _, err := exec.LookPath(v2binary) + return err == nil +} diff --git a/integration-cli/requirements_test.go b/integration-cli/requirements_test.go index 455be53dab..1462ab2a3e 100644 --- a/integration-cli/requirements_test.go +++ b/integration-cli/requirements_test.go @@ -105,14 +105,6 @@ func Apparmor() bool { return err == nil && len(buf) > 1 && buf[0] == 'Y' } -func RegistryHosting() bool { - // for now registry binary is built only if we're running inside - // container through `make test`. Figure that out by testing if - // registry binary is in PATH. - _, err := exec.LookPath(v2binary) - return err == nil -} - func NotaryHosting() bool { // for now notary binary is built only if we're running inside // container through `make test`. Figure that out by testing if