Skip to content

Commit ad7010d

Browse files
authored
feat(image-cri-shim): sync inline registries to registry.d (#6075)
feat: sync inline registries to registry.d
1 parent da87d76 commit ad7010d

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

lifecycle/staging/src/github.com/labring/image-cri-shim/pkg/types/config.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package types
1818

1919
import (
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

6870
type ShimAuthConfig struct {
@@ -78,6 +80,9 @@ func registryMatchDomain(reg Registry) string {
7880

7981
func (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+
211287
func loadRegistriesFromDir(dir string) ([]Registry, error) {
212288
files, err := listRegistryConfigFiles(dir)
213289
if err != nil {

lifecycle/staging/src/github.com/labring/image-cri-shim/pkg/types/config_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,55 @@ func TestRegistriesLoadedFromDir(t *testing.T) {
7777
t.Fatalf("expected credentials for 192.168.64.1:5000, got %#v", auth.CRIConfigs["192.168.64.1:5000"])
7878
}
7979
}
80+
81+
func TestRegistriesFieldSyncedToDir(t *testing.T) {
82+
dir := t.TempDir()
83+
registries := []Registry{
84+
{Address: "https://hub.192.168.64.4.nip.io", Auth: "admin:syncpass"},
85+
{Address: "http://192.168.64.1:5000"},
86+
}
87+
88+
cfg := &Config{
89+
ImageShimSocket: "/var/run/image-cri-shim.sock",
90+
RuntimeSocket: "/run/containerd/containerd.sock",
91+
Address: "https://registry.internal",
92+
Force: true,
93+
Auth: "sync:user",
94+
RegistryDir: dir,
95+
Registries: registries,
96+
}
97+
98+
auth, err := cfg.PreProcess()
99+
if err != nil {
100+
t.Fatalf("preprocess with inline registries failed: %v", err)
101+
}
102+
103+
expectedFiles := map[string]Registry{
104+
"hub.192.168.64.4.nip.io.yaml": registries[0],
105+
"192.168.64.1:5000.yaml": registries[1],
106+
}
107+
for name, want := range expectedFiles {
108+
path := filepath.Join(dir, name)
109+
data, err := os.ReadFile(path)
110+
if err != nil {
111+
t.Fatalf("expected registry file %s to be written: %v", path, err)
112+
}
113+
var got Registry
114+
if err := yaml.Unmarshal(data, &got); err != nil {
115+
t.Fatalf("failed to parse registry file %s: %v", path, err)
116+
}
117+
if got != want {
118+
t.Fatalf("registry file %s content mismatch: got %#v, want %#v", path, got, want)
119+
}
120+
}
121+
122+
firstDomain := registryMatchDomain(registries[0])
123+
if authCfg, ok := auth.CRIConfigs[firstDomain]; !ok || authCfg.Username != "admin" || authCfg.Password != "syncpass" {
124+
t.Fatalf("expected credentials for %s, got %#v", firstDomain, auth.CRIConfigs[firstDomain])
125+
}
126+
127+
secondDomain := registryMatchDomain(registries[1])
128+
if !auth.SkipLoginRegistries[secondDomain] {
129+
t.Fatalf("expected %s to skip login, got %#v", secondDomain, auth.SkipLoginRegistries)
130+
}
131+
}

0 commit comments

Comments
 (0)