@@ -28,6 +28,7 @@ import (
28
28
transfertypes "github.com/containerd/containerd/v2/api/types/transfer"
29
29
"github.com/containerd/containerd/v2/core/remotes"
30
30
"github.com/containerd/containerd/v2/core/remotes/docker"
31
+ "github.com/containerd/containerd/v2/core/remotes/docker/config"
31
32
"github.com/containerd/containerd/v2/core/streaming"
32
33
"github.com/containerd/containerd/v2/core/transfer"
33
34
"github.com/containerd/containerd/v2/core/transfer/plugins"
@@ -42,37 +43,73 @@ func init() {
42
43
plugins .Register (& transfertypes.OCIRegistry {}, & OCIRegistry {})
43
44
}
44
45
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
+
45
79
// 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 {
50
92
// 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 )
53
95
if err != nil {
54
96
return "" , "" , err
55
97
}
56
98
57
99
return c .Username , c .Secret , nil
58
- }))
59
- }
60
-
61
- ropts := []docker.RegistryOpt {
62
- docker .WithAuthorizer (docker .NewDockerAuthorizer (aopts ... )),
100
+ }
63
101
}
64
-
65
- // TODO: Apply local configuration, maybe dynamically create resolver when requested
66
102
resolver := docker .NewResolver (docker.ResolverOptions {
67
- Hosts : docker . ConfigureDefaultRegistries ( ropts ... ),
68
- Headers : headers ,
103
+ Hosts : config . ConfigureHosts ( ctx , hostOptions ),
104
+ Headers : ropts . headers ,
69
105
})
70
106
return & OCIRegistry {
71
107
reference : ref ,
72
- headers : headers ,
73
- creds : creds ,
108
+ headers : ropts . headers ,
109
+ creds : ropts . creds ,
74
110
resolver : resolver ,
75
- }
111
+ hostDir : ropts .hostDir ,
112
+ }, nil
76
113
}
77
114
78
115
// From stream
@@ -96,6 +133,8 @@ type OCIRegistry struct {
96
133
97
134
resolver remotes.Resolver
98
135
136
+ hostDir string
137
+
99
138
// This could be an interface which returns resolver?
100
139
// Resolver could also be a plug-able interface, to call out to a program to fetch?
101
140
}
@@ -194,6 +233,7 @@ func (r *OCIRegistry) MarshalAny(ctx context.Context, sm streaming.StreamCreator
194
233
}()
195
234
res .AuthStream = sid
196
235
}
236
+ res .HostDir = r .hostDir
197
237
s := & transfertypes.OCIRegistry {
198
238
Reference : r .reference ,
199
239
Resolver : res ,
@@ -203,16 +243,16 @@ func (r *OCIRegistry) MarshalAny(ctx context.Context, sm streaming.StreamCreator
203
243
}
204
244
205
245
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
211
247
if err := typeurl .UnmarshalTo (a , & s ); err != nil {
212
248
return err
213
249
}
214
250
251
+ hostOptions := config.HostOptions {}
215
252
if s .Resolver != nil {
253
+ if s .Resolver .HostDir != "" {
254
+ hostOptions .HostDir = config .HostDirFromRoot (s .Resolver .HostDir )
255
+ }
216
256
if sid := s .Resolver .AuthStream ; sid != "" {
217
257
stream , err := sm .Get (ctx , sid )
218
258
if err != nil {
@@ -222,26 +262,24 @@ func (r *OCIRegistry) UnmarshalAny(ctx context.Context, sm streaming.StreamGette
222
262
r .creds = & credCallback {
223
263
stream : stream ,
224
264
}
225
- aopts = append ( aopts , docker . WithAuthCreds ( func (host string ) (string , string , error ) {
265
+ hostOptions . Credentials = func (host string ) (string , string , error ) {
226
266
c , err := r .creds .GetCredentials (context .Background (), s .Reference , host )
227
267
if err != nil {
228
268
return "" , "" , err
229
269
}
230
270
231
271
return c .Username , c .Secret , nil
232
- }))
272
+ }
233
273
}
234
274
r .headers = http.Header {}
235
275
for k , v := range s .Resolver .Headers {
236
276
r .headers .Add (k , v )
237
277
}
238
278
}
239
- authorizer := docker .NewDockerAuthorizer (aopts ... )
240
- ropts = append (ropts , docker .WithAuthorizer (authorizer ))
241
279
242
280
r .reference = s .Reference
243
281
r .resolver = docker .NewResolver (docker.ResolverOptions {
244
- Hosts : docker . ConfigureDefaultRegistries ( ropts ... ),
282
+ Hosts : config . ConfigureHosts ( ctx , hostOptions ),
245
283
Headers : r .headers ,
246
284
})
247
285
0 commit comments