@@ -17,6 +17,7 @@ limitations under the License.
1717package types
1818
1919import (
20+ "bytes"
2021 "crypto/sha256"
2122 "errors"
2223 "fmt"
@@ -63,6 +64,7 @@ type Config struct {
6364 ReloadInterval metav1.Duration `json:"reloadInterval"`
6465 Auth string `json:"auth"`
6566 RegistryDir string `json:"registry.d"`
67+ Registries []Registry `json:"registries" yaml:"registries,omitempty"`
6668}
6769
6870type ShimAuthConfig struct {
@@ -78,6 +80,9 @@ func registryMatchDomain(reg Registry) string {
7880
7981func (c * Config ) PreProcess () (* ShimAuthConfig , error ) {
8082 c .RegistryDir = NormalizeRegistryDir (c .RegistryDir )
83+ if err := syncRegistriesToDir (c .RegistryDir , c .Registries ); err != nil {
84+ return nil , err
85+ }
8186 registries , err := loadRegistriesFromDir (c .RegistryDir )
8287 if err != nil {
8388 return nil , err
@@ -208,6 +213,77 @@ func NormalizeRegistryDir(dir string) string {
208213 return dir
209214}
210215
216+ func syncRegistriesToDir (dir string , registries []Registry ) error {
217+ if len (registries ) == 0 {
218+ return nil
219+ }
220+
221+ dir = NormalizeRegistryDir (dir )
222+ if err := os .MkdirAll (dir , 0o755 ); err != nil {
223+ return fmt .Errorf ("ensure registry.d %s: %w" , dir , err )
224+ }
225+
226+ for _ , reg := range registries {
227+ address := strings .TrimSpace (reg .Address )
228+ if address == "" {
229+ continue
230+ }
231+
232+ host := registryFileName (address )
233+ if host == "" {
234+ logger .Warn ("skip registry entry %q: unable to determine filename" , address )
235+ continue
236+ }
237+
238+ data , err := yaml .Marshal (reg )
239+ if err != nil {
240+ return fmt .Errorf ("marshal registry %s: %w" , host , err )
241+ }
242+
243+ path := filepath .Join (dir , fmt .Sprintf ("%s.yaml" , host ))
244+ if existing , err := os .ReadFile (path ); err == nil {
245+ if bytes .Equal (bytes .TrimSpace (existing ), bytes .TrimSpace (data )) {
246+ continue
247+ }
248+ } else if ! errors .Is (err , fs .ErrNotExist ) {
249+ return fmt .Errorf ("read registry config %s: %w" , path , err )
250+ }
251+
252+ if err := os .WriteFile (path , data , 0o644 ); err != nil {
253+ return fmt .Errorf ("write registry config %s: %w" , path , err )
254+ }
255+ logger .Debug ("synced registry config to %s" , path )
256+ }
257+
258+ return nil
259+ }
260+
261+ func registryFileName (address string ) string {
262+ if address == "" {
263+ return ""
264+ }
265+
266+ raw := strings .TrimSpace (address )
267+ if raw == "" {
268+ return ""
269+ }
270+
271+ if u , err := url .Parse (raw ); err == nil {
272+ host := u .Host
273+ if host != "" {
274+ return host
275+ }
276+ // Some registry addresses might be provided without scheme, causing Parse to treat them as paths.
277+ }
278+
279+ trimmed := strings .TrimPrefix (raw , "http://" )
280+ trimmed = strings .TrimPrefix (trimmed , "https://" )
281+ if idx := strings .Index (trimmed , "/" ); idx != - 1 {
282+ trimmed = trimmed [:idx ]
283+ }
284+ return strings .TrimSpace (trimmed )
285+ }
286+
211287func loadRegistriesFromDir (dir string ) ([]Registry , error ) {
212288 files , err := listRegistryConfigFiles (dir )
213289 if err != nil {
0 commit comments