Separate init blob upload
Pushing a v2 image layer has two steps: - POST to get a new upload URL - PUT to that upload URL We were previously not checking the response code of the POST request and the PUT would fail in weird ways. Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
This commit is contained in:
parent
4377a9a3bc
commit
bcccf35bb2
1 changed files with 49 additions and 18 deletions
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
@ -209,29 +210,14 @@ func (r *Session) GetV2ImageBlobReader(ep *Endpoint, imageName, sumType, sum str
|
||||||
// 'layer' is an uncompressed reader of the blob to be pushed.
|
// 'layer' is an uncompressed reader of the blob to be pushed.
|
||||||
// The server will generate it's own checksum calculation.
|
// The server will generate it's own checksum calculation.
|
||||||
func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName, sumType, sumStr string, blobRdr io.Reader, auth *RequestAuthorization) error {
|
func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName, sumType, sumStr string, blobRdr io.Reader, auth *RequestAuthorization) error {
|
||||||
routeURL, err := getV2Builder(ep).BuildBlobUploadURL(imageName)
|
location, err := r.initiateBlobUpload(ep, imageName, auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("[registry] Calling %q %s", "POST", routeURL)
|
|
||||||
req, err := r.reqFactory.NewRequest("POST", routeURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := auth.Authorize(req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
res, _, err := r.doRequest(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
location := res.Header.Get("Location")
|
|
||||||
|
|
||||||
method := "PUT"
|
method := "PUT"
|
||||||
log.Debugf("[registry] Calling %q %s", method, location)
|
log.Debugf("[registry] Calling %q %s", method, location)
|
||||||
req, err = r.reqFactory.NewRequest(method, location, ioutil.NopCloser(blobRdr))
|
req, err := r.reqFactory.NewRequest(method, location, ioutil.NopCloser(blobRdr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -241,7 +227,7 @@ func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName, sumType, sumStr string
|
||||||
if err := auth.Authorize(req); err != nil {
|
if err := auth.Authorize(req); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
res, _, err = r.doRequest(req)
|
res, _, err := r.doRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -262,6 +248,51 @@ func (r *Session) PutV2ImageBlob(ep *Endpoint, imageName, sumType, sumStr string
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initiateBlobUpload gets the blob upload location for the given image name.
|
||||||
|
func (r *Session) initiateBlobUpload(ep *Endpoint, imageName string, auth *RequestAuthorization) (location string, err error) {
|
||||||
|
routeURL, err := getV2Builder(ep).BuildBlobUploadURL(imageName)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("[registry] Calling %q %s", "POST", routeURL)
|
||||||
|
req, err := r.reqFactory.NewRequest("POST", routeURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := auth.Authorize(req); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
res, _, err := r.doRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != http.StatusAccepted {
|
||||||
|
if res.StatusCode == http.StatusUnauthorized {
|
||||||
|
return "", errLoginRequired
|
||||||
|
}
|
||||||
|
if res.StatusCode == http.StatusNotFound {
|
||||||
|
return "", ErrDoesNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
errBody, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Unexpected response from server: %q %#v", errBody, res.Header)
|
||||||
|
return "", utils.NewHTTPRequestError(fmt.Sprintf("Server error: unexpected %d response status trying to initiate upload of %s", res.StatusCode, imageName), res)
|
||||||
|
}
|
||||||
|
|
||||||
|
if location = res.Header.Get("Location"); location == "" {
|
||||||
|
return "", fmt.Errorf("registry did not return a Location header for resumable blob upload for image %s", imageName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Finally Push the (signed) manifest of the blobs we've just pushed
|
// Finally Push the (signed) manifest of the blobs we've just pushed
|
||||||
func (r *Session) PutV2ImageManifest(ep *Endpoint, imageName, tagName string, manifestRdr io.Reader, auth *RequestAuthorization) (string, error) {
|
func (r *Session) PutV2ImageManifest(ep *Endpoint, imageName, tagName string, manifestRdr io.Reader, auth *RequestAuthorization) (string, error) {
|
||||||
routeURL, err := getV2Builder(ep).BuildManifestURL(imageName, tagName)
|
routeURL, err := getV2Builder(ep).BuildManifestURL(imageName, tagName)
|
||||||
|
|
Loading…
Reference in a new issue