Skip to content

Commit 7a3b7fb

Browse files
committed
Transfer: Registry: Enable to use registry configuration diretory
Currently transfer service isn't aware of configurations of hosts directory and ctr's `--hosts-dir` doesn't work. This commit fixes this issue by using `config.ConfigureHosts` instead of `docker.ConfigureDefaultRegistries`. This commit also fixes ctr to use this feature for "--hosts-dir" flag. Signed-off-by: Kohei Tokunaga <[email protected]>
1 parent 7f0f49b commit 7a3b7fb

File tree

6 files changed

+124
-63
lines changed

6 files changed

+124
-63
lines changed

api/next.pb.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7461,6 +7461,13 @@ file {
74617461
type_name: ".containerd.types.transfer.RegistryResolver.HeadersEntry"
74627462
json_name: "headers"
74637463
}
7464+
field {
7465+
name: "host_dir"
7466+
number: 3
7467+
label: LABEL_OPTIONAL
7468+
type: TYPE_STRING
7469+
json_name: "hostDir"
7470+
}
74647471
nested_type {
74657472
name: "HeadersEntry"
74667473
field {

api/types/transfer/registry.pb.go

Lines changed: 42 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/types/transfer/registry.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ message RegistryResolver {
3535
// Headers
3636
map<string, string> headers = 2;
3737

38-
// Allow custom hosts dir?
38+
string host_dir = 3;
3939
// Force skip verify
4040
// Force HTTP
4141
// CA callback? Client TLS callback?

cmd/ctr/commands/images/pull.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ command. As part of this process, we do the following:
132132
sopts = append(sopts, image.WithAllMetadata)
133133
}
134134

135-
reg := registry.NewOCIRegistry(ref, nil, ch)
135+
reg, err := registry.NewOCIRegistry(ctx, ref, registry.WithCredentials(ch), registry.WithHostDir(context.String("hosts-dir")))
136+
if err != nil {
137+
return err
138+
}
136139
is := image.NewStore(ref, sopts...)
137140

138141
pf, done := ProgressHandler(ctx, os.Stdout)

cmd/ctr/commands/images/push.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ var pushCommand = &cli.Command{
104104
if local == "" {
105105
local = ref
106106
}
107-
reg := registry.NewOCIRegistry(ref, nil, ch)
107+
reg, err := registry.NewOCIRegistry(ctx, ref, registry.WithCredentials(ch), registry.WithHostDir(context.String("hosts-dir")))
108+
if err != nil {
109+
return err
110+
}
108111
is := image.NewStore(local)
109112

110113
pf, done := ProgressHandler(ctx, os.Stdout)

core/transfer/registry/registry.go

Lines changed: 66 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
transfertypes "github.com/containerd/containerd/v2/api/types/transfer"
2929
"github.com/containerd/containerd/v2/core/remotes"
3030
"github.com/containerd/containerd/v2/core/remotes/docker"
31+
"github.com/containerd/containerd/v2/core/remotes/docker/config"
3132
"github.com/containerd/containerd/v2/core/streaming"
3233
"github.com/containerd/containerd/v2/core/transfer"
3334
"github.com/containerd/containerd/v2/core/transfer/plugins"
@@ -42,37 +43,73 @@ func init() {
4243
plugins.Register(&transfertypes.OCIRegistry{}, &OCIRegistry{})
4344
}
4445

46+
type registryOpts struct {
47+
headers http.Header
48+
creds CredentialHelper
49+
hostDir string
50+
}
51+
52+
// Opt sets registry-related configurations.
53+
type Opt func(o *registryOpts) error
54+
55+
// WithHeaders configures HTTP request header fields sent by the resolver.
56+
func WithHeaders(headers http.Header) Opt {
57+
return func(o *registryOpts) error {
58+
o.headers = headers
59+
return nil
60+
}
61+
}
62+
63+
// WithCredentials configures a helper that provides credentials for a host.
64+
func WithCredentials(creds CredentialHelper) Opt {
65+
return func(o *registryOpts) error {
66+
o.creds = creds
67+
return nil
68+
}
69+
}
70+
71+
// WithHostDir specifies the host configuration directory.
72+
func WithHostDir(hostDir string) Opt {
73+
return func(o *registryOpts) error {
74+
o.hostDir = hostDir
75+
return nil
76+
}
77+
}
78+
4579
// NewOCIRegistry initializes with hosts, authorizer callback, and headers
46-
func NewOCIRegistry(ref string, headers http.Header, creds CredentialHelper) *OCIRegistry {
47-
// Create an authorizer
48-
var aopts []docker.AuthorizerOpt
49-
if creds != nil {
80+
func NewOCIRegistry(ctx context.Context, ref string, opts ...Opt) (*OCIRegistry, error) {
81+
var ropts registryOpts
82+
for _, o := range opts {
83+
if err := o(&ropts); err != nil {
84+
return nil, err
85+
}
86+
}
87+
hostOptions := config.HostOptions{}
88+
if ropts.hostDir != "" {
89+
hostOptions.HostDir = config.HostDirFromRoot(ropts.hostDir)
90+
}
91+
if ropts.creds != nil {
5092
// TODO: Support bearer
51-
aopts = append(aopts, docker.WithAuthCreds(func(host string) (string, string, error) {
52-
c, err := creds.GetCredentials(context.Background(), ref, host)
93+
hostOptions.Credentials = func(host string) (string, string, error) {
94+
c, err := ropts.creds.GetCredentials(context.Background(), ref, host)
5395
if err != nil {
5496
return "", "", err
5597
}
5698

5799
return c.Username, c.Secret, nil
58-
}))
59-
}
60-
61-
ropts := []docker.RegistryOpt{
62-
docker.WithAuthorizer(docker.NewDockerAuthorizer(aopts...)),
100+
}
63101
}
64-
65-
// TODO: Apply local configuration, maybe dynamically create resolver when requested
66102
resolver := docker.NewResolver(docker.ResolverOptions{
67-
Hosts: docker.ConfigureDefaultRegistries(ropts...),
68-
Headers: headers,
103+
Hosts: config.ConfigureHosts(ctx, hostOptions),
104+
Headers: ropts.headers,
69105
})
70106
return &OCIRegistry{
71107
reference: ref,
72-
headers: headers,
73-
creds: creds,
108+
headers: ropts.headers,
109+
creds: ropts.creds,
74110
resolver: resolver,
75-
}
111+
hostDir: ropts.hostDir,
112+
}, nil
76113
}
77114

78115
// From stream
@@ -96,6 +133,8 @@ type OCIRegistry struct {
96133

97134
resolver remotes.Resolver
98135

136+
hostDir string
137+
99138
// This could be an interface which returns resolver?
100139
// Resolver could also be a plug-able interface, to call out to a program to fetch?
101140
}
@@ -194,6 +233,7 @@ func (r *OCIRegistry) MarshalAny(ctx context.Context, sm streaming.StreamCreator
194233
}()
195234
res.AuthStream = sid
196235
}
236+
res.HostDir = r.hostDir
197237
s := &transfertypes.OCIRegistry{
198238
Reference: r.reference,
199239
Resolver: res,
@@ -203,16 +243,16 @@ func (r *OCIRegistry) MarshalAny(ctx context.Context, sm streaming.StreamCreator
203243
}
204244

205245
func (r *OCIRegistry) UnmarshalAny(ctx context.Context, sm streaming.StreamGetter, a typeurl.Any) error {
206-
var (
207-
s transfertypes.OCIRegistry
208-
ropts []docker.RegistryOpt
209-
aopts []docker.AuthorizerOpt
210-
)
246+
var s transfertypes.OCIRegistry
211247
if err := typeurl.UnmarshalTo(a, &s); err != nil {
212248
return err
213249
}
214250

251+
hostOptions := config.HostOptions{}
215252
if s.Resolver != nil {
253+
if s.Resolver.HostDir != "" {
254+
hostOptions.HostDir = config.HostDirFromRoot(s.Resolver.HostDir)
255+
}
216256
if sid := s.Resolver.AuthStream; sid != "" {
217257
stream, err := sm.Get(ctx, sid)
218258
if err != nil {
@@ -222,26 +262,24 @@ func (r *OCIRegistry) UnmarshalAny(ctx context.Context, sm streaming.StreamGette
222262
r.creds = &credCallback{
223263
stream: stream,
224264
}
225-
aopts = append(aopts, docker.WithAuthCreds(func(host string) (string, string, error) {
265+
hostOptions.Credentials = func(host string) (string, string, error) {
226266
c, err := r.creds.GetCredentials(context.Background(), s.Reference, host)
227267
if err != nil {
228268
return "", "", err
229269
}
230270

231271
return c.Username, c.Secret, nil
232-
}))
272+
}
233273
}
234274
r.headers = http.Header{}
235275
for k, v := range s.Resolver.Headers {
236276
r.headers.Add(k, v)
237277
}
238278
}
239-
authorizer := docker.NewDockerAuthorizer(aopts...)
240-
ropts = append(ropts, docker.WithAuthorizer(authorizer))
241279

242280
r.reference = s.Reference
243281
r.resolver = docker.NewResolver(docker.ResolverOptions{
244-
Hosts: docker.ConfigureDefaultRegistries(ropts...),
282+
Hosts: config.ConfigureHosts(ctx, hostOptions),
245283
Headers: r.headers,
246284
})
247285

0 commit comments

Comments
 (0)