dockergosdk

Unable to push images using Go SDK for Docker


I'm trying to push an image to Docker hub using the Go SDK library. Pulling the image, tagging etc. works but I'm unable to push the image.

The program also throws no errors.

package main

import (
    "context"
    "encoding/base64"
    "encoding/json"

    "github.com/docker/docker/api/types"
    "github.com/docker/docker/client"
)

func check(err error) {
    if err != nil {
        panic(err)
    }
}

func main() {
    ctx := context.Background()

    cli, err := client.NewEnvClient()
    check(err)

    err = cli.ImageTag(ctx, "alpine:3", "docker.io/jerrymannel/alpine:3")
    check(err)

    authConfig := types.AuthConfig{
        Username: "<username>",
        Password: "<password>",
    }
    encodedJSON, err := json.Marshal(authConfig)
    check(err)
    authStr := base64.URLEncoding.EncodeToString(encodedJSON)

    _, err = cli.ImagePush(ctx, "docker.io/jerrymannel/alpine:3", types.ImagePushOptions{
        RegistryAuth: authStr,
    })
    check(err)

}

Solution

  • After spending a day behind this, I found the solution 5 mins after asking this question.

    I was giving the wrong username and password. The cli.ImagePush() method doesn't return an error if the username or password is wrong.

    Modified the last lines like this,

    pusher, err := cli.ImagePush(ctx, "docker.io/jerrymannel/alpine:3", types.ImagePushOptions{
        RegistryAuth: authStr,
    })
    check(err)
    
    defer pusher.Close()
    io.Copy(os.Stdout, pusher)
    

    That showed the following message -

    {"errorDetail":{"message":"unauthorized: incorrect username or password"},"error":"unauthorized: incorrect username or password"}
    

    Gave the correct password and now it's working.

    [updated]

    There's an open defect for this Defect 36253

    For now, here's the code for handling the error.

    pusher, err := cli.ImagePush(ctx, "docker.io/jerrymannel/alpine:3", types.ImagePushOptions{
        RegistryAuth: authStr,
    })
    check(err)
    defer pusher.Close()
    
    type ErrorMessage struct {
        Error string
    }
    var errorMessage ErrorMessage
    buffIOReader := bufio.NewReader(pusher)
    
    for {
        streamBytes, err := buffIOReader.ReadBytes('\n')
        if err == io.EOF {
            break
        }
        json.Unmarshal(streamBytes, &errorMessage)
        if errorMessage.Error != "" {
            panic(errorMessage.Error)
        }
    }