Skip to content

Commit beebe0d

Browse files
committed
feat(image): introduce WithCredentials* to select how pull credentials are retrieved
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent d8207cc commit beebe0d

File tree

2 files changed

+62
-26
lines changed

2 files changed

+62
-26
lines changed

image/options.go

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package image
22

33
import (
44
"errors"
5+
"fmt"
56
"io"
67

8+
"github.com/docker/go-sdk/config"
79
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
810

911
"github.com/docker/docker/api/types/build"
@@ -39,9 +41,41 @@ func WithBuildOptions(options build.ImageBuildOptions) BuildOption {
3941
type PullOption func(*pullOptions) error
4042

4143
type pullOptions struct {
42-
pullClient ImagePullClient
43-
pullOptions image.PullOptions
44-
pullHandler func(r io.ReadCloser) error
44+
pullClient ImagePullClient
45+
pullOptions image.PullOptions
46+
pullHandler func(r io.ReadCloser) error
47+
credentialsFn func(string) (string, string, error)
48+
}
49+
50+
// WithCredentialsFn set the function to retrieve credentials for an image to be pulled
51+
func WithCredentialsFn(credentialsFn func(string) (string, string, error)) PullOption {
52+
return func(opts *pullOptions) error {
53+
opts.credentialsFn = credentialsFn
54+
return nil
55+
}
56+
}
57+
58+
// WithCredentialsFromConfig configures pull to retrieve credentials from the CLI config
59+
func WithCredentialsFromConfig() PullOption {
60+
return func(opts *pullOptions) error {
61+
opts.credentialsFn = func(imageName string) (string, string, error) {
62+
authConfigs, err := config.AuthConfigs(imageName)
63+
if err != nil {
64+
return "", "", err
65+
}
66+
67+
// there must be only one auth config for the image
68+
if len(authConfigs) > 1 {
69+
return "", "", fmt.Errorf("multiple auth configs found for image %s, expected only one", imageName)
70+
}
71+
72+
for _, ac := range authConfigs {
73+
return ac.Username, ac.Password, nil
74+
}
75+
return "", "", nil
76+
}
77+
return nil
78+
}
4579
}
4680

4781
// WithPullClient sets the pull client used to pull the image.

image/pull.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -54,37 +54,39 @@ func Pull(ctx context.Context, imageName string, opts ...PullOption) error {
5454
defer pullOpts.pullClient.Close()
5555
}
5656

57+
if pullOpts.credentialsFn == nil {
58+
if err := WithCredentialsFromConfig()(pullOpts); err != nil {
59+
return fmt.Errorf("set credentials for pull option: %w", err)
60+
}
61+
}
62+
5763
if imageName == "" {
5864
return errors.New("image name is not set")
5965
}
6066

61-
authConfigs, err := config.AuthConfigs(imageName)
62-
if err != nil {
63-
pullOpts.pullClient.Logger().Warn("failed to get image auth, setting empty credentials for the image", "image", imageName, "error", err)
64-
} else {
65-
// there must be only one auth config for the image
66-
if len(authConfigs) > 1 {
67-
return fmt.Errorf("multiple auth configs found for image %s, expected only one", imageName)
68-
}
69-
70-
var tmp config.AuthConfig
71-
for _, ac := range authConfigs {
72-
tmp = ac
73-
}
74-
75-
authConfig := config.AuthConfig{
76-
Username: tmp.Username,
77-
Password: tmp.Password,
78-
}
79-
encodedJSON, err := json.Marshal(authConfig)
67+
if pullOpts.credentialsFn == nil {
68+
username, password, err := pullOpts.credentialsFn(imageName)
8069
if err != nil {
81-
pullOpts.pullClient.Logger().Warn("failed to marshal image auth, setting empty credentials for the image", "image", imageName, "error", err)
82-
} else {
83-
pullOpts.pullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON)
70+
return fmt.Errorf("failed to retrieve credentials for image %s: %w", imageName, err)
71+
}
72+
if username != "" && password != "" {
73+
authConfig := config.AuthConfig{
74+
Username: username,
75+
Password: password,
76+
}
77+
encodedJSON, err := json.Marshal(authConfig)
78+
if err != nil {
79+
pullOpts.pullClient.Logger().Warn("failed to marshal image auth, setting empty credentials for the image", "image", imageName, "error", err)
80+
} else {
81+
pullOpts.pullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON)
82+
}
8483
}
8584
}
8685

87-
var pull io.ReadCloser
86+
var (
87+
pull io.ReadCloser
88+
err error
89+
)
8890
err = backoff.RetryNotify(
8991
func() error {
9092
pull, err = pullOpts.pullClient.ImagePull(ctx, imageName, pullOpts.pullOptions)

0 commit comments

Comments
 (0)