diff --git a/docs/registry_mock_test.go b/docs/registry_mock_test.go index 60173578..eab87d46 100644 --- a/docs/registry_mock_test.go +++ b/docs/registry_mock_test.go @@ -81,6 +81,7 @@ var ( testRepositories = map[string]map[string]string{ "foo42/bar": { "latest": "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d", + "test": "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d", }, } mockHosts = map[string][]net.IP{ diff --git a/docs/registry_test.go b/docs/registry_test.go index eee801d4..bb2761c5 100644 --- a/docs/registry_test.go +++ b/docs/registry_test.go @@ -211,18 +211,33 @@ func TestGetRemoteImageLayer(t *testing.T) { } } +func TestGetRemoteTag(t *testing.T) { + r := spawnTestRegistrySession(t) + tag, err := r.GetRemoteTag([]string{makeURL("/v1/")}, REPO, "test") + if err != nil { + t.Fatal(err) + } + assertEqual(t, tag, imageID, "Expected tag test to map to "+imageID) + + _, err = r.GetRemoteTag([]string{makeURL("/v1/")}, "foo42/baz", "foo") + if err != ErrRepoNotFound { + t.Fatal("Expected ErrRepoNotFound error when fetching tag for bogus repo") + } +} + func TestGetRemoteTags(t *testing.T) { r := spawnTestRegistrySession(t) tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO) if err != nil { t.Fatal(err) } - assertEqual(t, len(tags), 1, "Expected one tag") + assertEqual(t, len(tags), 2, "Expected two tags") assertEqual(t, tags["latest"], imageID, "Expected tag latest to map to "+imageID) + assertEqual(t, tags["test"], imageID, "Expected tag test to map to "+imageID) _, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz") - if err == nil { - t.Fatal("Expected error when fetching tags for bogus repo") + if err != ErrRepoNotFound { + t.Fatal("Expected ErrRepoNotFound error when fetching tags for bogus repo") } } diff --git a/docs/session.go b/docs/session.go index ca1f8e49..573a03bf 100644 --- a/docs/session.go +++ b/docs/session.go @@ -26,6 +26,10 @@ import ( "github.com/docker/docker/pkg/transport" ) +var ( + ErrRepoNotFound = errors.New("Repository not found") +) + type Session struct { indexEndpoint *Endpoint client *http.Client @@ -279,6 +283,38 @@ func (r *Session) GetRemoteImageLayer(imgID, registry string, imgSize int64) (io return res.Body, nil } +func (r *Session) GetRemoteTag(registries []string, repository string, askedTag string) (string, error) { + if strings.Count(repository, "/") == 0 { + // This will be removed once the Registry supports auto-resolution on + // the "library" namespace + repository = "library/" + repository + } + for _, host := range registries { + endpoint := fmt.Sprintf("%srepositories/%s/tags/%s", host, repository, askedTag) + res, err := r.client.Get(endpoint) + if err != nil { + return "", err + } + + logrus.Debugf("Got status code %d from %s", res.StatusCode, endpoint) + defer res.Body.Close() + + if res.StatusCode == 404 { + return "", ErrRepoNotFound + } + if res.StatusCode != 200 { + continue + } + + var tagId string + if err := json.NewDecoder(res.Body).Decode(&tagId); err != nil { + return "", err + } + return tagId, nil + } + return "", fmt.Errorf("Could not reach any registry endpoint") +} + func (r *Session) GetRemoteTags(registries []string, repository string) (map[string]string, error) { if strings.Count(repository, "/") == 0 { // This will be removed once the Registry supports auto-resolution on @@ -296,7 +332,7 @@ func (r *Session) GetRemoteTags(registries []string, repository string) (map[str defer res.Body.Close() if res.StatusCode == 404 { - return nil, fmt.Errorf("Repository not found") + return nil, ErrRepoNotFound } if res.StatusCode != 200 { continue