heroku / docker-registry-client

A Go API client for the v2 Docker Registry API
BSD 3-Clause "New" or "Revised" License
297 stars 225 forks source link

trying to clone one repository to another repository #8

Open codervinod opened 8 years ago

codervinod commented 8 years ago

Hi, I am working on a project which needs me to copy one repository to another. My UploadLayer calls are failing. I keep getting this fault http: ContentLength=32 with Body length 0

Could you please help?

Thanks, Vinod

exists, err := hub.HasLayer("abc/hello-abc-test1", digest)

    if err != nil {
        return nil, err
    }

    if exists {
        fmt.Printf("layer exists\n")
        continue
    }

    reader, err := hub.DownloadLayer("codervinod/hello-prism", digest)
    if err != nil {
        fmt.Printf(" Error downloading layer %s\n", err)    
        return nil, err
    }

    if reader != nil {          
            buf, err := ioutil.ReadAll(reader)
            if err != nil {
                return nil, err
            }
            layer_content := bytes.NewBuffer(buf)
            fmt.Printf("Recieved byffer of length %d\n", layer_content.Len())

            err = hub.UploadLayer("abc/hello-prism-test1", digest, layer_content)
            if err != nil {
                fmt.Printf(" Error uploading image %s\n", err)  
                defer reader.Close()
                return nil, err
            }

        defer reader.Close()
    }

    fmt.Printf("Uploaded layer\n")
kispaljr commented 5 years ago

Hi,

neither UploadBlob() (former UploadLayer()), nor PutManifest() is working properly in case of token authentication (see details). More precisely they cannot resend the body of the request after the 401 Unauthorized response, because the content reader is not reusable.

Another way to reproduce the issue:

    username, password := "<your DockerHub username>", "<your DockerHub password>"
    repository := username + "/docker-registry-client-test"
    registry, err := New("https://registry-1.docker.io", username, password)
    if err != nil {
        log.Fatal("couldn't connect to registry:", err)
    }

    blobData := []byte("This is a test blob.")
    digest := digest.FromBytes(blobData)
    content := bytes.NewBuffer(blobData)
    err = registry.UploadBlob(repository, digest, content)
    if err != nil {
        log.Fatal("couldn't upload blob:", err)
    }

This will result in the same error: http: ContentLength=20 with Body length 0. If a file is given instead of buffer, the error becomes: file already closed

The problem is that in TokenTransport.retry() the HTTP PUT request is resent with the same Body, but by that time all (or at least some) bytes were already read from the corresponding Reader.

kispaljr commented 5 years ago

@codervinod, could you rename the issue to reflect that UploadBlob() and all other HTTP requests with a non-empty body, are broken in case of token authentication?