@@ -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
205245func (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