@@ -17,14 +17,17 @@ limitations under the License.
17
17
package e2enode
18
18
19
19
import (
20
+ "context"
20
21
"fmt"
21
22
"os"
22
23
"os/exec"
23
24
"os/user"
25
+ "sync"
24
26
"time"
25
27
26
28
"k8s.io/klog/v2"
27
29
30
+ utilerrors "k8s.io/apimachinery/pkg/util/errors"
28
31
"k8s.io/apimachinery/pkg/util/sets"
29
32
internalapi "k8s.io/cri-api/pkg/apis"
30
33
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
@@ -41,6 +44,8 @@ const (
41
44
maxImagePullRetries = 5
42
45
// Sleep duration between image pull retry attempts.
43
46
imagePullRetryDelay = time .Second
47
+ // Number of parallel count to pull images.
48
+ maxParallelImagePullCount = 5
44
49
)
45
50
46
51
// NodePrePullImageList is a list of images used in node e2e test. These images will be prepulled
@@ -151,27 +156,61 @@ func PrePullAllImages() error {
151
156
}
152
157
images := framework .ImagePrePullList .List ()
153
158
klog .V (4 ).Infof ("Pre-pulling images with %s %+v" , puller .Name (), images )
154
- for _ , image := range images {
155
- var (
156
- err error
157
- output []byte
158
- )
159
- for i := 0 ; i < maxImagePullRetries ; i ++ {
160
- if i > 0 {
161
- time .Sleep (imagePullRetryDelay )
162
- }
163
- if output , err = puller .Pull (image ); err == nil {
164
- break
159
+
160
+ imageCh := make (chan int , len (images ))
161
+ for i := range images {
162
+ imageCh <- i
163
+ }
164
+ close (imageCh )
165
+
166
+ pullErrs := make ([]error , len (images ))
167
+ ctx , cancel := context .WithCancel (context .Background ())
168
+ defer cancel ()
169
+
170
+ parallelImagePullCount := maxParallelImagePullCount
171
+ if len (images ) < parallelImagePullCount {
172
+ parallelImagePullCount = len (images )
173
+ }
174
+
175
+ var wg sync.WaitGroup
176
+ wg .Add (parallelImagePullCount )
177
+ for i := 0 ; i < parallelImagePullCount ; i ++ {
178
+ go func () {
179
+ defer wg .Done ()
180
+
181
+ for i := range imageCh {
182
+ var (
183
+ pullErr error
184
+ output []byte
185
+ )
186
+ for retryCount := 0 ; retryCount < maxImagePullRetries ; retryCount ++ {
187
+ select {
188
+ case <- ctx .Done ():
189
+ return
190
+ default :
191
+ }
192
+
193
+ if retryCount > 0 {
194
+ time .Sleep (imagePullRetryDelay )
195
+ }
196
+ if output , pullErr = puller .Pull (images [i ]); pullErr == nil {
197
+ break
198
+ }
199
+ klog .Warningf ("Failed to pull %s as user %q, retrying in %s (%d of %d): %v" ,
200
+ images [i ], usr .Username , imagePullRetryDelay .String (), retryCount + 1 , maxImagePullRetries , pullErr )
201
+ }
202
+ if pullErr != nil {
203
+ klog .Warningf ("Could not pre-pull image %s %v output: %s" , images [i ], pullErr , output )
204
+ pullErrs [i ] = pullErr
205
+ cancel ()
206
+ return
207
+ }
165
208
}
166
- klog .Warningf ("Failed to pull %s as user %q, retrying in %s (%d of %d): %v" ,
167
- image , usr .Username , imagePullRetryDelay .String (), i + 1 , maxImagePullRetries , err )
168
- }
169
- if err != nil {
170
- klog .Warningf ("Could not pre-pull image %s %v output: %s" , image , err , output )
171
- return err
172
- }
209
+ }()
173
210
}
174
- return nil
211
+
212
+ wg .Wait ()
213
+ return utilerrors .NewAggregate (pullErrs )
175
214
}
176
215
177
216
// getGPUDevicePluginImage returns the image of GPU device plugin.
0 commit comments