forked from TrueCloudLab/distribution
Add tags implementation
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
parent
2eb9b286ed
commit
7d630192dd
4 changed files with 98 additions and 25 deletions
|
@ -112,3 +112,10 @@ func parseHTTPErrorResponse(response *http.Response) error {
|
||||||
}
|
}
|
||||||
return &errors
|
return &errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleErrorResponse(resp *http.Response) error {
|
||||||
|
if resp.StatusCode >= 400 && resp.StatusCode < 500 {
|
||||||
|
return parseHTTPErrorResponse(resp)
|
||||||
|
}
|
||||||
|
return &UnexpectedHTTPStatusError{Status: resp.Status}
|
||||||
|
}
|
||||||
|
|
|
@ -26,14 +26,10 @@ type httpLayerUpload struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hlu *httpLayerUpload) handleErrorResponse(resp *http.Response) error {
|
func (hlu *httpLayerUpload) handleErrorResponse(resp *http.Response) error {
|
||||||
switch {
|
if resp.StatusCode == http.StatusNotFound {
|
||||||
case resp.StatusCode == http.StatusNotFound:
|
|
||||||
return &BlobUploadNotFoundError{Location: hlu.location}
|
return &BlobUploadNotFoundError{Location: hlu.location}
|
||||||
case resp.StatusCode >= 400 && resp.StatusCode < 500:
|
|
||||||
return parseHTTPErrorResponse(resp)
|
|
||||||
default:
|
|
||||||
return &UnexpectedHTTPStatusError{Status: resp.Status}
|
|
||||||
}
|
}
|
||||||
|
return handleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hlu *httpLayerUpload) ReadFrom(r io.Reader) (n int64, err error) {
|
func (hlu *httpLayerUpload) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -90,7 +91,36 @@ type manifests struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *manifests) Tags() ([]string, error) {
|
func (ms *manifests) Tags() ([]string, error) {
|
||||||
panic("not implemented")
|
u, err := ms.ub.BuildTagsURL(ms.name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := ms.client.Get(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case resp.StatusCode == http.StatusOK:
|
||||||
|
b, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tagsResponse := struct {
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
}{}
|
||||||
|
if err := json.Unmarshal(b, &tagsResponse); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tagsResponse.Tags, nil
|
||||||
|
case resp.StatusCode == http.StatusNotFound:
|
||||||
|
return nil, nil
|
||||||
|
default:
|
||||||
|
return nil, handleErrorResponse(resp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *manifests) Exists(dgst digest.Digest) (bool, error) {
|
func (ms *manifests) Exists(dgst digest.Digest) (bool, error) {
|
||||||
|
@ -113,10 +143,8 @@ func (ms *manifests) ExistsByTag(tag string) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
case resp.StatusCode == http.StatusNotFound:
|
case resp.StatusCode == http.StatusNotFound:
|
||||||
return false, nil
|
return false, nil
|
||||||
case resp.StatusCode >= 400 && resp.StatusCode < 500:
|
|
||||||
return false, parseHTTPErrorResponse(resp)
|
|
||||||
default:
|
default:
|
||||||
return false, &UnexpectedHTTPStatusError{Status: resp.Status}
|
return false, handleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,10 +174,8 @@ func (ms *manifests) GetByTag(tag string) (*manifest.SignedManifest, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &sm, nil
|
return &sm, nil
|
||||||
case resp.StatusCode >= 400 && resp.StatusCode < 500:
|
|
||||||
return nil, parseHTTPErrorResponse(resp)
|
|
||||||
default:
|
default:
|
||||||
return nil, &UnexpectedHTTPStatusError{Status: resp.Status}
|
return nil, handleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,10 +200,8 @@ func (ms *manifests) Put(m *manifest.SignedManifest) error {
|
||||||
case resp.StatusCode == http.StatusAccepted:
|
case resp.StatusCode == http.StatusAccepted:
|
||||||
// TODO(dmcgowan): Use or check digest header
|
// TODO(dmcgowan): Use or check digest header
|
||||||
return nil
|
return nil
|
||||||
case resp.StatusCode >= 400 && resp.StatusCode < 500:
|
|
||||||
return parseHTTPErrorResponse(resp)
|
|
||||||
default:
|
default:
|
||||||
return &UnexpectedHTTPStatusError{Status: resp.Status}
|
return handleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,10 +224,8 @@ func (ms *manifests) Delete(dgst digest.Digest) error {
|
||||||
switch {
|
switch {
|
||||||
case resp.StatusCode == http.StatusOK:
|
case resp.StatusCode == http.StatusOK:
|
||||||
return nil
|
return nil
|
||||||
case resp.StatusCode >= 400 && resp.StatusCode < 500:
|
|
||||||
return parseHTTPErrorResponse(resp)
|
|
||||||
default:
|
default:
|
||||||
return &UnexpectedHTTPStatusError{Status: resp.Status}
|
return handleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,10 +297,8 @@ func (ls *layers) Upload() (distribution.LayerUpload, error) {
|
||||||
startedAt: time.Now(),
|
startedAt: time.Now(),
|
||||||
location: location,
|
location: location,
|
||||||
}, nil
|
}, nil
|
||||||
case resp.StatusCode >= 400 && resp.StatusCode < 500:
|
|
||||||
return nil, parseHTTPErrorResponse(resp)
|
|
||||||
default:
|
default:
|
||||||
return nil, &UnexpectedHTTPStatusError{Status: resp.Status}
|
return nil, handleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,9 +347,7 @@ func (ls *layers) fetchLayer(dgst digest.Digest) (distribution.Layer, error) {
|
||||||
BlobSum: dgst,
|
BlobSum: dgst,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case resp.StatusCode >= 400 && resp.StatusCode < 500:
|
|
||||||
return nil, parseHTTPErrorResponse(resp)
|
|
||||||
default:
|
default:
|
||||||
return nil, &UnexpectedHTTPStatusError{Status: resp.Status}
|
return nil, handleErrorResponse(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -602,3 +603,54 @@ func TestManifestPut(t *testing.T) {
|
||||||
|
|
||||||
// TODO(dmcgowan): Check for error cases
|
// TODO(dmcgowan): Check for error cases
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestManifestTags(t *testing.T) {
|
||||||
|
repo := "test.example.com/repo/tags/list"
|
||||||
|
tagsList := []byte(strings.TrimSpace(`
|
||||||
|
{
|
||||||
|
"name": "test.example.com/repo/tags/list",
|
||||||
|
"tags": [
|
||||||
|
"tag1",
|
||||||
|
"tag2",
|
||||||
|
"funtag"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`))
|
||||||
|
var m testutil.RequestResponseMap
|
||||||
|
addPing(&m)
|
||||||
|
m = append(m, testutil.RequestResponseMapping{
|
||||||
|
Request: testutil.Request{
|
||||||
|
Method: "GET",
|
||||||
|
Route: "/v2/" + repo + "/tags/list",
|
||||||
|
},
|
||||||
|
Response: testutil.Response{
|
||||||
|
StatusCode: http.StatusOK,
|
||||||
|
Body: tagsList,
|
||||||
|
Headers: http.Header(map[string][]string{
|
||||||
|
"Content-Length": {fmt.Sprint(len(tagsList))},
|
||||||
|
"Last-Modified": {time.Now().Add(-1 * time.Second).Format(time.ANSIC)},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
e, c := testServer(m)
|
||||||
|
defer c()
|
||||||
|
|
||||||
|
r, err := NewRepository(context.Background(), repo, e, &RepositoryConfig{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ms := r.Manifests()
|
||||||
|
tags, err := ms.Tags()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tags) != 3 {
|
||||||
|
t.Fatalf("Wrong number of tags returned: %d, expected 3", len(tags))
|
||||||
|
}
|
||||||
|
// TODO(dmcgowan): Check array
|
||||||
|
|
||||||
|
// TODO(dmcgowan): Check for error cases
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue