From 64c8bd29ccecbcdf5f9c6f56eec05915703b5293 Mon Sep 17 00:00:00 2001 From: Brian Bland Date: Wed, 19 Nov 2014 18:52:09 -0800 Subject: [PATCH] Uses new digest package instead of string digests Also drops extraneous test package and uses testutil instead --- client/client.go | 27 ++++++----- client/client_test.go | 55 +++++++++++----------- client/objectstore.go | 11 +++-- test/test.go => common/testutil/handler.go | 2 +- errors.go | 4 +- images.go | 3 +- 6 files changed, 54 insertions(+), 48 deletions(-) rename test/test.go => common/testutil/handler.go (99%) diff --git a/client/client.go b/client/client.go index 8eb156c51..944050e07 100644 --- a/client/client.go +++ b/client/client.go @@ -11,6 +11,7 @@ import ( "strconv" "github.com/docker/docker-registry" + "github.com/docker/docker-registry/digest" ) // Client implements the client interface to the registry http api @@ -33,13 +34,13 @@ type Client interface { // BlobLength returns the length of the blob stored at the given name, // digest pair. // Returns a length value of -1 on error or if the blob does not exist. - BlobLength(name, digest string) (int, error) + BlobLength(name string, dgst digest.Digest) (int, error) // GetBlob returns the blob stored at the given name, digest pair in the // form of an io.ReadCloser with the length of this blob. // A nonzero byteOffset can be provided to receive a partial blob beginning // at the given offset. - GetBlob(name, digest string, byteOffset int) (io.ReadCloser, int, error) + GetBlob(name string, dgst digest.Digest, byteOffset int) (io.ReadCloser, int, error) // InitiateBlobUpload starts a blob upload in the given repository namespace // and returns a unique location url to use for other blob upload methods. @@ -50,7 +51,7 @@ type Client interface { GetBlobUploadStatus(location string) (int, int, error) // UploadBlob uploads a full blob to the registry. - UploadBlob(location string, blob io.ReadCloser, length int, digest string) error + UploadBlob(location string, blob io.ReadCloser, length int, dgst digest.Digest) error // UploadBlobChunk uploads a blob chunk with a given length and startByte to // the registry. @@ -59,7 +60,7 @@ type Client interface { // FinishChunkedBlobUpload completes a chunked blob upload at a given // location. - FinishChunkedBlobUpload(location string, length int, digest string) error + FinishChunkedBlobUpload(location string, length int, dgst digest.Digest) error // CancelBlobUpload deletes all content at the unfinished blob upload // location and invalidates any future calls to this blob upload. @@ -222,8 +223,8 @@ func (r *clientImpl) ListImageTags(name string) ([]string, error) { return tags.Tags, nil } -func (r *clientImpl) BlobLength(name, digest string) (int, error) { - response, err := http.Head(fmt.Sprintf("%s/v2/%s/blob/%s", r.Endpoint, name, digest)) +func (r *clientImpl) BlobLength(name string, dgst digest.Digest) (int, error) { + response, err := http.Head(fmt.Sprintf("%s/v2/%s/blob/%s", r.Endpoint, name, dgst)) if err != nil { return -1, err } @@ -254,9 +255,9 @@ func (r *clientImpl) BlobLength(name, digest string) (int, error) { } } -func (r *clientImpl) GetBlob(name, digest string, byteOffset int) (io.ReadCloser, int, error) { +func (r *clientImpl) GetBlob(name string, dgst digest.Digest, byteOffset int) (io.ReadCloser, int, error) { getRequest, err := http.NewRequest("GET", - fmt.Sprintf("%s/v2/%s/blob/%s", r.Endpoint, name, digest), nil) + fmt.Sprintf("%s/v2/%s/blob/%s", r.Endpoint, name, dgst), nil) if err != nil { return nil, 0, err } @@ -278,7 +279,7 @@ func (r *clientImpl) GetBlob(name, digest string, byteOffset int) (io.ReadCloser return response.Body, int(length), nil case response.StatusCode == http.StatusNotFound: response.Body.Close() - return nil, 0, ®istry.BlobNotFoundError{Name: name, Digest: digest} + return nil, 0, ®istry.BlobNotFoundError{Name: name, Digest: dgst} case response.StatusCode >= 400 && response.StatusCode < 500: errors := new(registry.Errors) decoder := json.NewDecoder(response.Body) @@ -351,7 +352,7 @@ func (r *clientImpl) GetBlobUploadStatus(location string) (int, int, error) { } } -func (r *clientImpl) UploadBlob(location string, blob io.ReadCloser, length int, digest string) error { +func (r *clientImpl) UploadBlob(location string, blob io.ReadCloser, length int, dgst digest.Digest) error { defer blob.Close() putRequest, err := http.NewRequest("PUT", @@ -362,7 +363,7 @@ func (r *clientImpl) UploadBlob(location string, blob io.ReadCloser, length int, queryValues := url.Values{} queryValues.Set("length", fmt.Sprint(length)) - queryValues.Set("digest", digest) + queryValues.Set("digest", dgst.String()) putRequest.URL.RawQuery = queryValues.Encode() putRequest.Header.Set("Content-Type", "application/octet-stream") @@ -444,7 +445,7 @@ func (r *clientImpl) UploadBlobChunk(location string, blobChunk io.ReadCloser, l } } -func (r *clientImpl) FinishChunkedBlobUpload(location string, length int, digest string) error { +func (r *clientImpl) FinishChunkedBlobUpload(location string, length int, dgst digest.Digest) error { putRequest, err := http.NewRequest("PUT", fmt.Sprintf("%s%s", r.Endpoint, location), nil) if err != nil { @@ -453,7 +454,7 @@ func (r *clientImpl) FinishChunkedBlobUpload(location string, length int, digest queryValues := new(url.Values) queryValues.Set("length", fmt.Sprint(length)) - queryValues.Set("digest", digest) + queryValues.Set("digest", dgst.String()) putRequest.URL.RawQuery = queryValues.Encode() putRequest.Header.Set("Content-Type", "application/octet-stream") diff --git a/client/client_test.go b/client/client_test.go index 9840ae44e..a77e7665e 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -10,11 +10,12 @@ import ( "testing" "github.com/docker/docker-registry" - "github.com/docker/docker-registry/test" + "github.com/docker/docker-registry/common/testutil" + "github.com/docker/docker-registry/digest" ) type testBlob struct { - digest string + digest digest.Digest contents []byte } @@ -42,7 +43,7 @@ func TestPush(t *testing.T) { // to change at some point. uploadLocations[i] = fmt.Sprintf("/v2/%s/blob/test-uuid", name) blobs[i] = registry.FSLayer{BlobSum: blob.digest} - history[i] = registry.ManifestHistory{V1Compatibility: blob.digest} + history[i] = registry.ManifestHistory{V1Compatibility: blob.digest.String()} } manifest := ®istry.ImageManifest{ @@ -55,44 +56,44 @@ func TestPush(t *testing.T) { } manifestBytes, err := json.Marshal(manifest) - blobRequestResponseMappings := make([]test.RequestResponseMapping, 2*len(testBlobs)) + blobRequestResponseMappings := make([]testutil.RequestResponseMapping, 2*len(testBlobs)) for i, blob := range testBlobs { - blobRequestResponseMappings[2*i] = test.RequestResponseMapping{ - Request: test.Request{ + blobRequestResponseMappings[2*i] = testutil.RequestResponseMapping{ + Request: testutil.Request{ Method: "POST", Route: "/v2/" + name + "/blob/upload/", }, - Response: test.Response{ + Response: testutil.Response{ StatusCode: http.StatusAccepted, Headers: http.Header(map[string][]string{ "Location": {uploadLocations[i]}, }), }, } - blobRequestResponseMappings[2*i+1] = test.RequestResponseMapping{ - Request: test.Request{ + blobRequestResponseMappings[2*i+1] = testutil.RequestResponseMapping{ + Request: testutil.Request{ Method: "PUT", Route: uploadLocations[i], QueryParams: map[string][]string{ "length": {fmt.Sprint(len(blob.contents))}, - "digest": {blob.digest}, + "digest": {blob.digest.String()}, }, Body: blob.contents, }, - Response: test.Response{ + Response: testutil.Response{ StatusCode: http.StatusCreated, }, } } - handler := test.NewHandler(append(blobRequestResponseMappings, test.RequestResponseMap{ - test.RequestResponseMapping{ - Request: test.Request{ + handler := testutil.NewHandler(append(blobRequestResponseMappings, testutil.RequestResponseMap{ + testutil.RequestResponseMapping{ + Request: testutil.Request{ Method: "PUT", Route: "/v2/" + name + "/manifest/" + tag, Body: manifestBytes, }, - Response: test.Response{ + Response: testutil.Response{ StatusCode: http.StatusOK, }, }, @@ -102,7 +103,7 @@ func TestPush(t *testing.T) { objectStore := &memoryObjectStore{ mutex: new(sync.Mutex), manifestStorage: make(map[string]*registry.ImageManifest), - layerStorage: make(map[string]Layer), + layerStorage: make(map[digest.Digest]Layer), } for _, blob := range testBlobs { @@ -146,7 +147,7 @@ func TestPull(t *testing.T) { for i, blob := range testBlobs { blobs[i] = registry.FSLayer{BlobSum: blob.digest} - history[i] = registry.ManifestHistory{V1Compatibility: blob.digest} + history[i] = registry.ManifestHistory{V1Compatibility: blob.digest.String()} } manifest := ®istry.ImageManifest{ @@ -159,27 +160,27 @@ func TestPull(t *testing.T) { } manifestBytes, err := json.Marshal(manifest) - blobRequestResponseMappings := make([]test.RequestResponseMapping, len(testBlobs)) + blobRequestResponseMappings := make([]testutil.RequestResponseMapping, len(testBlobs)) for i, blob := range testBlobs { - blobRequestResponseMappings[i] = test.RequestResponseMapping{ - Request: test.Request{ + blobRequestResponseMappings[i] = testutil.RequestResponseMapping{ + Request: testutil.Request{ Method: "GET", - Route: "/v2/" + name + "/blob/" + blob.digest, + Route: "/v2/" + name + "/blob/" + blob.digest.String(), }, - Response: test.Response{ + Response: testutil.Response{ StatusCode: http.StatusOK, Body: blob.contents, }, } } - handler := test.NewHandler(append(blobRequestResponseMappings, test.RequestResponseMap{ - test.RequestResponseMapping{ - Request: test.Request{ + handler := testutil.NewHandler(append(blobRequestResponseMappings, testutil.RequestResponseMap{ + testutil.RequestResponseMapping{ + Request: testutil.Request{ Method: "GET", Route: "/v2/" + name + "/manifest/" + tag, }, - Response: test.Response{ + Response: testutil.Response{ StatusCode: http.StatusOK, Body: manifestBytes, }, @@ -190,7 +191,7 @@ func TestPull(t *testing.T) { objectStore := &memoryObjectStore{ mutex: new(sync.Mutex), manifestStorage: make(map[string]*registry.ImageManifest), - layerStorage: make(map[string]Layer), + layerStorage: make(map[digest.Digest]Layer), } err = Pull(client, objectStore, name, tag) diff --git a/client/objectstore.go b/client/objectstore.go index d8e2ac763..bee73ff07 100644 --- a/client/objectstore.go +++ b/client/objectstore.go @@ -9,6 +9,7 @@ import ( "sync" "github.com/docker/docker-registry" + "github.com/docker/docker-registry/digest" ) var ( @@ -34,7 +35,7 @@ type ObjectStore interface { WriteManifest(name, tag string, manifest *registry.ImageManifest) error // Layer returns a handle to a layer for reading and writing - Layer(blobSum string) (Layer, error) + Layer(dgst digest.Digest) (Layer, error) } // Layer is a generic image layer interface. @@ -56,7 +57,7 @@ type Layer interface { type memoryObjectStore struct { mutex *sync.Mutex manifestStorage map[string]*registry.ImageManifest - layerStorage map[string]Layer + layerStorage map[digest.Digest]Layer } func (objStore *memoryObjectStore) Manifest(name, tag string) (*registry.ImageManifest, error) { @@ -78,14 +79,14 @@ func (objStore *memoryObjectStore) WriteManifest(name, tag string, manifest *reg return nil } -func (objStore *memoryObjectStore) Layer(blobSum string) (Layer, error) { +func (objStore *memoryObjectStore) Layer(dgst digest.Digest) (Layer, error) { objStore.mutex.Lock() defer objStore.mutex.Unlock() - layer, ok := objStore.layerStorage[blobSum] + layer, ok := objStore.layerStorage[dgst] if !ok { layer = &memoryLayer{cond: sync.NewCond(new(sync.Mutex))} - objStore.layerStorage[blobSum] = layer + objStore.layerStorage[dgst] = layer } return layer, nil diff --git a/test/test.go b/common/testutil/handler.go similarity index 99% rename from test/test.go rename to common/testutil/handler.go index 24a08f756..fa118cd1b 100644 --- a/test/test.go +++ b/common/testutil/handler.go @@ -1,4 +1,4 @@ -package test +package testutil import ( "bytes" diff --git a/errors.go b/errors.go index bb59a5afe..9a28e5b69 100644 --- a/errors.go +++ b/errors.go @@ -3,6 +3,8 @@ package registry import ( "fmt" "strings" + + "github.com/docker/docker-registry/digest" ) // ErrorCode represents the error type. The errors are serialized via strings @@ -228,7 +230,7 @@ func (e *ImageManifestNotFoundError) Error() string { // layer that does not exist in the registry. type BlobNotFoundError struct { Name string - Digest string + Digest digest.Digest } func (e *BlobNotFoundError) Error() string { diff --git a/images.go b/images.go index e30c6a5fd..534069b26 100644 --- a/images.go +++ b/images.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" + "github.com/docker/docker-registry/digest" "github.com/gorilla/handlers" ) @@ -52,7 +53,7 @@ func (m *ImageManifest) UnmarshalJSON(b []byte) error { // FSLayer is a container struct for BlobSums defined in an image manifest type FSLayer struct { // BlobSum is the tarsum of the referenced filesystem image layer - BlobSum string `json:"blobSum"` + BlobSum digest.Digest `json:"blobSum"` } // ManifestHistory stores unstructured v1 compatibility information