@@ -4,10 +4,20 @@ import (
44 "os"
55 "os/exec"
66 "runtime"
7+ "strings"
8+ "time"
79
810 log "github.com/newrelic/newrelic-diagnostics-cli/logger"
911)
1012
13+ // dockerBuildRetryPatterns are transient errors seen on Windows CI runners
14+ // that are worth retrying rather than failing the whole test.
15+ var dockerBuildRetryPatterns = []string {
16+ "hcs::CreateComputeSystem" ,
17+ "failed to connect to the docker API" ,
18+ "docker_engine" ,
19+ }
20+
1121func CreateDockerImage (imageName string , dockerFROM string , docker_cmd string , dockerLines []string ) error {
1222
1323 //Create the Dockerfile
@@ -19,14 +29,21 @@ func CreateDockerImage(imageName string, dockerFROM string, docker_cmd string, d
1929
2030 log .Debug ("Running docker build -f integrationDockerfile -t " , imageName , " ." )
2131
22- buildArgs := []string {"build" }
23- if runtime .GOOS == "windows" {
24- buildArgs = append (buildArgs , "--isolation=hyperv" )
32+ const maxAttempts = 3
33+ var output []byte
34+ var cmdBuildErr error
35+ for attempt := 1 ; attempt <= maxAttempts ; attempt ++ {
36+ cmdBuild := exec .Command ("docker" , "build" , "-f" , dockerfile , "-t" , imageName , "." )
37+ output , cmdBuildErr = cmdBuild .CombinedOutput ()
38+ if cmdBuildErr == nil {
39+ break
40+ }
41+ if attempt == maxAttempts || ! isTransientDockerError (string (output )) {
42+ break
43+ }
44+ log .Info ("Transient docker build error for " , imageName , " (attempt " , attempt , " of " , maxAttempts , "), retrying in " , attempt * 5 , "s" )
45+ time .Sleep (time .Duration (attempt * 5 ) * time .Second )
2546 }
26- buildArgs = append (buildArgs , "-f" , dockerfile , "-t" , imageName , "." )
27- cmdBuild := exec .Command ("docker" , buildArgs ... )
28-
29- output , cmdBuildErr := cmdBuild .CombinedOutput ()
3047
3148 if cmdBuildErr != nil {
3249 log .Info ("Error running docker build -" , cmdBuildErr )
@@ -37,6 +54,15 @@ func CreateDockerImage(imageName string, dockerFROM string, docker_cmd string, d
3754 return nil
3855}
3956
57+ func isTransientDockerError (output string ) bool {
58+ for _ , pattern := range dockerBuildRetryPatterns {
59+ if strings .Contains (output , pattern ) {
60+ return true
61+ }
62+ }
63+ return false
64+ }
65+
4066// CreateDockerfile - This builds the raw Dockerfile from the slice of tests
4167func CreateDockerfile (imageName string , dockerFROM string , dockerCMD string , dockerfileLines []string ) (string , error ) {
4268 f , _ := os .CreateTemp ("temp" , imageName )
@@ -120,9 +146,6 @@ func RunDockerContainer(imageName string, hostsAdditions []string) (string, erro
120146 //Create docker container based on test name
121147
122148 args := []string {"run" , "--rm" }
123- if runtime .GOOS == "windows" {
124- args = append (args , "--isolation=hyperv" )
125- }
126149 if len (hostsAdditions ) > 0 {
127150 for _ , hostAddition := range hostsAdditions {
128151 args = append (args , "--add-host" , hostAddition )
0 commit comments