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 <vincent@sbr.pm>
This commit is contained in:
Vincent Demeester 2016-12-30 19:10:04 +01:00
parent 5374d53322
commit 4300e5e881
No known key found for this signature in database
GPG Key ID: 083CC6FD6EB699A3
13 changed files with 168 additions and 123 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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.

View File

@ -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)
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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.

View File

@ -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")
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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