Skip to content

Commit e882f44

Browse files
authored
Gerard/sc 106216/b registry image collector (#1570)
* update registry auth with username and password * add unit test
1 parent d79ff95 commit e882f44

File tree

2 files changed

+91
-3
lines changed

2 files changed

+91
-3
lines changed

pkg/collect/registry.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
"k8s.io/client-go/kubernetes"
2323
"k8s.io/client-go/rest"
24+
"k8s.io/klog/v2"
2425
)
2526

2627
type RegistryImage struct {
@@ -97,6 +98,7 @@ func imageExists(namespace string, clientConfig *rest.Config, registryCollector
9798

9899
authConfig, err := getImageAuthConfig(namespace, clientConfig, registryCollector, imageRef)
99100
if err != nil {
101+
klog.Errorf("failed to get auth config: %v", err)
100102
return false, errors.Wrap(err, "failed to get auth config")
101103
}
102104

@@ -115,10 +117,13 @@ func imageExists(namespace string, clientConfig *rest.Config, registryCollector
115117

116118
remoteImage, err := imageRef.NewImage(context.Background(), &sysCtx)
117119
if err == nil {
120+
klog.Infof("image %s exists", image)
118121
remoteImage.Close()
119122
return true, nil
120123
}
121124

125+
klog.Errorf("failed to get image %s: %v", image, err)
126+
122127
if strings.Contains(err.Error(), "no image found in manifest list for architecture") {
123128
// manifest was downloaded, but no matching architecture found in manifest
124129
// should this count as image does not exist?
@@ -188,7 +193,9 @@ func getImageAuthConfigFromData(imageRef types.ImageReference, pullSecrets *v1be
188193

189194
dockerCfgJSON := struct {
190195
Auths map[string]struct {
191-
Auth []byte `json:"auth"`
196+
Auth string `json:"auth"`
197+
Username string `json:"username"`
198+
Password string `json:"password"`
192199
} `json:"auths"`
193200
}{}
194201

@@ -203,14 +210,25 @@ func getImageAuthConfigFromData(imageRef types.ImageReference, pullSecrets *v1be
203210
return nil, nil
204211
}
205212

213+
// gcr.io auth uses username and password, e.g. username: _json_key, password: <sa_key>
214+
if auth.Username != "" && auth.Password != "" {
215+
return &registryAuthConfig{
216+
username: auth.Username,
217+
password: auth.Password,
218+
}, nil
219+
}
220+
221+
// docker.io auth uses auth, e.g. auth: <base64_encoded_username_password>
222+
// username and password can't contain colon
223+
// at least according to https://github.com/docker/cli/blob/v27.0.3/cli/config/configfile/file.go#L247
206224
parts := strings.Split(string(auth.Auth), ":")
207225
if len(parts) != 2 {
208-
return nil, errors.Errorf("expected 2 parts in the string, but found %d", len(parts))
226+
return nil, errors.Errorf("expected 2 parts in the auth string, but found %d", len(parts))
209227
}
210228

211229
authConfig := registryAuthConfig{
212230
username: parts[0],
213-
password: parts[1],
231+
password: strings.Trim(parts[1], "\x00"),
214232
}
215233

216234
return &authConfig, nil

pkg/collect/registry_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package collect
2+
3+
import (
4+
"encoding/base64"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/containers/image/v5/transports/alltransports"
9+
"github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestGetImageAuthConfigFromData(t *testing.T) {
14+
tests := []struct {
15+
name string
16+
imageName string
17+
dockerConfigJSON string
18+
expectedUsername string
19+
expectedPassword string
20+
expectedError bool
21+
}{
22+
{
23+
name: "docker.io auth",
24+
imageName: "docker.io/myimage",
25+
dockerConfigJSON: `{"auths":{"docker.io":{"auth":"username:password"}}}`,
26+
expectedUsername: "username",
27+
expectedPassword: "password",
28+
expectedError: false,
29+
},
30+
{
31+
name: "docker.io auth multi colon",
32+
imageName: "docker.io/myimage",
33+
dockerConfigJSON: `{"auths":{"docker.io":{"auth":"user:name:pass:word"}}}`,
34+
expectedError: true,
35+
},
36+
{
37+
name: "gcr.io auth",
38+
imageName: "gcr.io/myimage",
39+
dockerConfigJSON: `{"auths":{"gcr.io":{"username":"_json_key","password":"sa-key"}}}`,
40+
expectedUsername: "_json_key",
41+
expectedPassword: "sa-key",
42+
expectedError: false,
43+
},
44+
}
45+
46+
for _, test := range tests {
47+
t.Run(test.name, func(t *testing.T) {
48+
imageRef, err := alltransports.ParseImageName(fmt.Sprintf("docker://%s", test.imageName))
49+
assert.NoError(t, err)
50+
51+
pullSecrets := &v1beta2.ImagePullSecrets{
52+
SecretType: "kubernetes.io/dockerconfigjson",
53+
Data: map[string]string{
54+
".dockerconfigjson": base64.StdEncoding.EncodeToString([]byte(test.dockerConfigJSON)),
55+
},
56+
}
57+
58+
authConfig, err := getImageAuthConfigFromData(imageRef, pullSecrets)
59+
if test.expectedError {
60+
assert.Error(t, err)
61+
return
62+
}
63+
64+
assert.NoError(t, err)
65+
assert.NotNil(t, authConfig)
66+
assert.Equal(t, test.expectedUsername, authConfig.username)
67+
assert.Equal(t, test.expectedPassword, authConfig.password)
68+
})
69+
}
70+
}

0 commit comments

Comments
 (0)