@@ -24,8 +24,11 @@ import (
24
24
25
25
"github.com/google/go-containerregistry/pkg/authn"
26
26
"github.com/google/go-containerregistry/pkg/name"
27
+ v1 "github.com/google/go-containerregistry/pkg/v1"
27
28
"github.com/google/go-containerregistry/pkg/v1/layout"
28
29
"github.com/google/go-containerregistry/pkg/v1/remote"
30
+ "github.com/samber/lo"
31
+ "github.com/samber/lo/parallel"
29
32
30
33
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/contexts"
31
34
"github.com/deckhouse/deckhouse-cli/pkg/libmirror/util/auth"
@@ -41,9 +44,13 @@ func PushLayoutToRepo(
41
44
registryRepo string ,
42
45
authProvider authn.Authenticator ,
43
46
logger contexts.Logger ,
47
+ parallelismConfig contexts.ParallelismConfig ,
44
48
insecure , skipVerifyTLS bool ,
45
49
) error {
46
50
refOpts , remoteOpts := auth .MakeRemoteRegistryRequestOptions (authProvider , insecure , skipVerifyTLS )
51
+ if parallelismConfig .Blobs != 0 {
52
+ remoteOpts = append (remoteOpts , remote .WithJobs (parallelismConfig .Blobs ))
53
+ }
47
54
48
55
index , err := imagesLayout .ImageIndex ()
49
56
if err != nil {
@@ -58,40 +65,83 @@ func PushLayoutToRepo(
58
65
return fmt .Errorf ("%s: %w" , registryRepo , ErrEmptyLayout )
59
66
}
60
67
61
- pushCount := 1
62
- for _ , imageDesc := range indexManifest .Manifests {
63
- tag := imageDesc .Annotations ["io.deckhouse.image.short_tag" ]
64
- imageRef := registryRepo + ":" + tag
65
-
66
- img , err := index .Image (imageDesc .Digest )
68
+ batches := lo .Chunk (indexManifest .Manifests , parallelismConfig .Images )
69
+ batchesCount , imagesCount := 1 , 1
70
+
71
+ for _ , manifestSet := range batches {
72
+ err = logger .Process (fmt .Sprintf ("Pushing batch %d / %d" , batchesCount , len (batches )), func () error {
73
+ logger .InfoLn ("Images in batch:" )
74
+ for _ , manifest := range manifestSet {
75
+ tag := manifest .Annotations ["io.deckhouse.image.short_tag" ]
76
+ imageRef := registryRepo + ":" + tag
77
+ logger .InfoF ("- %s" , imageRef )
78
+ }
79
+
80
+ parallel .ForEach (
81
+ manifestSet ,
82
+ pushImage (logger , registryRepo , index , imagesCount , refOpts , remoteOpts ),
83
+ )
84
+
85
+ return nil
86
+ })
67
87
if err != nil {
68
- return fmt .Errorf ("Read image : %w" , err )
88
+ return fmt .Errorf ("Push batch of images : %w" , err )
69
89
}
90
+ batchesCount += 1
91
+ }
70
92
93
+ return nil
94
+ }
95
+
96
+ func pushImage (
97
+ logger contexts.Logger ,
98
+ registryRepo string ,
99
+ index v1.ImageIndex ,
100
+ imagesCount int ,
101
+ refOpts []name.Option ,
102
+ remoteOpts []remote.Option ,
103
+ ) func (v1.Descriptor , int ) {
104
+ return func (manifest v1.Descriptor , _ int ) {
105
+ tag := manifest .Annotations ["io.deckhouse.image.short_tag" ]
106
+ imageRef := registryRepo + ":" + tag
107
+ img , err := index .Image (manifest .Digest )
108
+ if err != nil {
109
+ logger .WarnF ("Read image: %v" , err )
110
+ os .Exit (1 )
111
+ }
71
112
ref , err := name .ParseReference (imageRef , refOpts ... )
72
113
if err != nil {
73
- return fmt .Errorf ("Parse image reference: %w" , err )
114
+ logger .WarnF ("Parse image reference: %v" , err )
115
+ os .Exit (1 )
74
116
}
75
117
76
- err = retry .RunTask (
77
- logger ,
78
- fmt .Sprintf ("[%d / %d] Pushing image %s " , pushCount , len (indexManifest .Manifests ), imageRef ),
79
- task .WithConstantRetries (19 , 3 * time .Second , func () error {
80
- if err = remote .Write (ref , img , remoteOpts ... ); err != nil {
81
- if errorutil .IsTrivyMediaTypeNotAllowedError (err ) {
82
- logger .WarnLn (errorutil .CustomTrivyMediaTypesWarning )
83
- os .Exit (1 )
84
- }
85
- return fmt .Errorf ("Write %s to registry: %w" , ref .String (), err )
118
+ err = retry .RunTask (silentLogger {}, "" , task .WithConstantRetries (19 , 3 * time .Second , func () error {
119
+ if err = remote .Write (ref , img , remoteOpts ... ); err != nil {
120
+ if errorutil .IsTrivyMediaTypeNotAllowedError (err ) {
121
+ logger .WarnLn (errorutil .CustomTrivyMediaTypesWarning )
122
+ os .Exit (1 )
86
123
}
87
- return nil
88
- }))
124
+ return fmt .Errorf ("Write %s to registry: %w" , ref .String (), err )
125
+ }
126
+ return nil
127
+ }))
89
128
if err != nil {
90
- return fmt .Errorf ("Push image: %w" , err )
129
+ logger .WarnF ("Push image: %v" , err )
130
+ os .Exit (1 )
91
131
}
92
132
93
- pushCount += 1
133
+ imagesCount += 1
94
134
}
95
-
96
- return nil
97
135
}
136
+
137
+ type silentLogger struct {}
138
+
139
+ var _ contexts.Logger = silentLogger {}
140
+
141
+ func (silentLogger ) DebugF (_ string , _ ... interface {}) {}
142
+ func (silentLogger ) DebugLn (_ ... interface {}) {}
143
+ func (silentLogger ) InfoF (_ string , _ ... interface {}) {}
144
+ func (silentLogger ) InfoLn (_ ... interface {}) {}
145
+ func (silentLogger ) WarnF (_ string , _ ... interface {}) {}
146
+ func (silentLogger ) WarnLn (_ ... interface {}) {}
147
+ func (silentLogger ) Process (_ string , _ func () error ) error { return nil }
0 commit comments