Skip to content

Commit 8c25f50

Browse files
committed
add sync skip
1 parent a793b58 commit 8c25f50

File tree

6 files changed

+163
-115
lines changed

6 files changed

+163
-115
lines changed

config/keys.go

Lines changed: 0 additions & 107 deletions
This file was deleted.

config/logging.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package config
2+
3+
var (
4+
// region Logging
5+
6+
// LoggingFormat defines the logging format used for log messages. Allowed values are "json" and "text".
7+
LoggingFormat = NewKey("logging.format",
8+
WithDefaultValue("text"),
9+
WithAllowedStrings([]string{"json", "text"}))
10+
11+
// LoggingColors specifies whether log messages are displayed with color-coded
12+
// output. This only applies when LoggingFormat is set to "text".
13+
LoggingColors = NewKey("logging.colors",
14+
WithDefaultValue(true),
15+
WithValidBool())
16+
17+
// LoggingTimeFormat specifies the time format used for log messages. The default is 15:04:05.
18+
LoggingTimeFormat = NewKey("logging.timeFormat",
19+
WithDefaultValue("15:04:05"))
20+
21+
// LoggingOutput specifies the destination where log messages created by the
22+
// application are sent. It defaults to stdout.
23+
LoggingOutput = NewKey("logging.output",
24+
WithDefaultValue("stdout"))
25+
26+
// LoggingLevel specifies the minimum severity a log message must meet to be
27+
// recorded.
28+
LoggingLevel = NewKey("logging.level",
29+
WithDefaultValue("INFO"),
30+
WithAllowedStrings([]string{"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "PANIC", "DISABLED"}))
31+
// endregion
32+
)

config/sync.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package config
2+
3+
var (
4+
// region Sync
5+
6+
// SyncMaxErrors specifies the maximum number of errors that can occur before the application exits.
7+
SyncMaxErrors = NewKey("sync.maxErrors",
8+
WithDefaultValue(5),
9+
WithValidInt())
10+
11+
// SyncInterval specifies the interval at which images are synchronized.
12+
SyncInterval = NewKey("sync.interval",
13+
WithDefaultValue("30m"),
14+
WithValidDuration())
15+
16+
// SyncMinInterval specifies the minimum interval at which images are synchronized if they were already synchronized before.
17+
SyncMinInterval = NewKey("sync.minInterval",
18+
WithDefaultValue("12h"),
19+
WithValidDuration())
20+
21+
// SyncRegistries specifies the repositories to use for pulling and pushing images.
22+
SyncRegistries = NewKey("sync.registries",
23+
WithDefaultValue([]map[string]interface{}{
24+
{
25+
"name": "Docker Hub",
26+
"url": "docker.io",
27+
"auth": map[string]interface{}{
28+
"username": "",
29+
"password": "",
30+
"token": "",
31+
"helper": "",
32+
},
33+
},
34+
}),
35+
WithValidRepositories())
36+
37+
// SyncImages specifies the images to synchronize.
38+
SyncImages = NewKey("sync.images",
39+
WithDefaultValue([]map[string]interface{}{
40+
{
41+
"source": "docker.io/library/ubuntu",
42+
"targets": []string{
43+
"docker.io/library/ubuntu",
44+
},
45+
"mutableTags": []string{
46+
"latest",
47+
},
48+
},
49+
}),
50+
WithValidImages())
51+
52+
// endregion
53+
)

config/telemetry.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package config
2+
3+
var (
4+
// region Telemetry
5+
6+
// TelemetryEnabled indicates whether telemetry is enabled.
7+
TelemetryEnabled = NewKey("telemetry.enabled",
8+
WithDefaultValue(false),
9+
WithValidBool())
10+
11+
// TelemetryMetricsExporter specifies the metrics exporter used for telemetry.
12+
TelemetryMetricsExporter = NewKey("telemetry.metrics.exporter",
13+
WithDefaultValue("prometheus"),
14+
WithAllowedStrings([]string{"prometheus", "stdout"}))
15+
16+
// TelemetryMetricsPrometheusAddress specifies the network address for the Prometheus
17+
TelemetryMetricsPrometheusAddress = NewKey("telemetry.metrics.prometheus.address",
18+
WithDefaultValue("127.0.0.1:9090"),
19+
WithValidNetHostPort())
20+
21+
// TelemetryMetricsPrometheusPath specifies the path for the Prometheus metrics endpoint.
22+
TelemetryMetricsPrometheusPath = NewKey("telemetry.metrics.prometheus.path",
23+
WithDefaultValue("/metrics"),
24+
WithValidURI())
25+
26+
// TelemetryMetricsStdoutInterval specifies the sampling interval for sending metrics to stdout.
27+
TelemetryMetricsStdoutInterval = NewKey("telemetry.metrics.stdout.interval",
28+
WithDefaultValue("5s"),
29+
WithValidDuration())
30+
// endregion
31+
)

internal/sync/tags.go

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,46 @@ func SyncTag(image *structs.Image, tag string, pullAuthName string, options ...r
2727
return err
2828
}
2929

30+
syncTargets := make(map[string]remote.Option)
31+
if image.Auths == nil {
32+
image.Auths = make(map[string]remote.Option)
33+
}
34+
35+
for _, target := range targets {
36+
tref, err := name.ParseReference(fmt.Sprintf("%s:%s", target, tag))
37+
if err != nil {
38+
merr = multierr.Append(merr, err)
39+
continue
40+
}
41+
42+
pushAuth, ok := image.Auths[target]
43+
if !ok {
44+
pushAuth, _ = getAuth(image.GetRegistry(target), image.GetRepository(target))
45+
image.Auths[target] = pushAuth
46+
}
47+
48+
if slices.Contains(image.MutableTags, tag) {
49+
syncTargets[target] = pushAuth
50+
continue
51+
}
52+
53+
_, err = remote.Index(tref, pushAuth)
54+
if err != nil {
55+
if strings.Contains(err.Error(), "MANIFEST_UNKNOWN") {
56+
syncTargets[target] = pushAuth
57+
continue
58+
}
59+
}
60+
}
61+
62+
if len(syncTargets) == 0 {
63+
log.Info().
64+
Str("source", image.Source).
65+
Str("tag", tag).
66+
Msg("Skipping tag sync, all targets are up to date")
67+
return nil
68+
}
69+
3070
index, err := remote.Index(ref, options...)
3171
if err != nil {
3272
if strings.Contains(err.Error(), "unsupported MediaType") {
@@ -61,22 +101,19 @@ func SyncTag(image *structs.Image, tag string, pullAuthName string, options ...r
61101
}
62102
}
63103

64-
for _, target := range targets {
104+
for target, pushAuth := range syncTargets {
65105
tref, err := name.ParseReference(fmt.Sprintf("%s:%s", target, tag))
66106
if err != nil {
67107
merr = multierr.Append(merr, err)
68108
continue
69109
}
70110

71-
pushAuth, pushAuthName := getAuth(image.GetRegistry(target), image.GetRepository(target))
72-
73111
log.Info().
74112
Str("source", image.Source).
75113
Str("tag", tag).
76114
Strs("requiredPlatforms", expectedPlatforms).
77115
Str("target", target).
78116
Str("pullAuth", pullAuthName).
79-
Str("pushAuth", pushAuthName).
80117
Msg("Syncing tag")
81118

82119
if err := remote.WriteIndex(tref, index, pushAuth); err != nil {

structs/image.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import (
88
)
99

1010
type Image struct {
11-
Source string `json:"source" yaml:"source"`
12-
Tags []string `json:"tags" yaml:"tags"`
13-
Targets []string `json:"targets" yaml:"targets"`
14-
RequiredPlatforms []string `json:"requiredPlatforms" yaml:"requiredPlatforms"`
11+
Source string `json:"source" yaml:"source"`
12+
Tags []string `json:"tags" yaml:"tags"`
13+
Targets []string `json:"targets" yaml:"targets"`
14+
RequiredPlatforms []string `json:"requiredPlatforms" yaml:"requiredPlatforms"`
15+
MutableTags []string `json:"mutableTags" yaml:"mutableTags"`
16+
Auths map[string]remote.Option `json:"-" yaml:"-"`
1517
}
1618

1719
func (i *Image) GetSource() string {

0 commit comments

Comments
 (0)