github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/internal/test/fixtures/load/frozen.go (about) 1 package load // import "github.com/docker/docker/internal/test/fixtures/load" 2 3 import ( 4 "bufio" 5 "bytes" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "strings" 10 "sync" 11 12 "context" 13 14 "github.com/docker/docker/api/types" 15 "github.com/docker/docker/client" 16 "github.com/docker/docker/pkg/jsonmessage" 17 "github.com/docker/docker/pkg/term" 18 "github.com/pkg/errors" 19 ) 20 21 const frozenImgDir = "/docker-frozen-images" 22 23 // FrozenImagesLinux loads the frozen image set for the integration suite 24 // If the images are not available locally it will download them 25 // TODO: This loads whatever is in the frozen image dir, regardless of what 26 // images were passed in. If the images need to be downloaded, then it will respect 27 // the passed in images 28 func FrozenImagesLinux(client client.APIClient, images ...string) error { 29 var loadImages []struct{ srcName, destName string } 30 for _, img := range images { 31 if !imageExists(client, img) { 32 srcName := img 33 // hello-world:latest gets re-tagged as hello-world:frozen 34 // there are some tests that use hello-world:latest specifically so it pulls 35 // the image and hello-world:frozen is used for when we just want a super 36 // small image 37 if img == "hello-world:frozen" { 38 srcName = "hello-world:latest" 39 } 40 loadImages = append(loadImages, struct{ srcName, destName string }{ 41 srcName: srcName, 42 destName: img, 43 }) 44 } 45 } 46 if len(loadImages) == 0 { 47 // everything is loaded, we're done 48 return nil 49 } 50 51 ctx := context.Background() 52 fi, err := os.Stat(frozenImgDir) 53 if err != nil || !fi.IsDir() { 54 srcImages := make([]string, 0, len(loadImages)) 55 for _, img := range loadImages { 56 srcImages = append(srcImages, img.srcName) 57 } 58 if err := pullImages(ctx, client, srcImages); err != nil { 59 return errors.Wrap(err, "error pulling image list") 60 } 61 } else { 62 if err := loadFrozenImages(ctx, client); err != nil { 63 return err 64 } 65 } 66 67 for _, img := range loadImages { 68 if img.srcName != img.destName { 69 if err := client.ImageTag(ctx, img.srcName, img.destName); err != nil { 70 return errors.Wrapf(err, "failed to tag %s as %s", img.srcName, img.destName) 71 } 72 if _, err := client.ImageRemove(ctx, img.srcName, types.ImageRemoveOptions{}); err != nil { 73 return errors.Wrapf(err, "failed to remove %s", img.srcName) 74 } 75 } 76 } 77 return nil 78 } 79 80 func imageExists(client client.APIClient, name string) bool { 81 _, _, err := client.ImageInspectWithRaw(context.Background(), name) 82 return err == nil 83 } 84 85 func loadFrozenImages(ctx context.Context, client client.APIClient) error { 86 tar, err := exec.LookPath("tar") 87 if err != nil { 88 return errors.Wrap(err, "could not find tar binary") 89 } 90 tarCmd := exec.Command(tar, "-cC", frozenImgDir, ".") 91 out, err := tarCmd.StdoutPipe() 92 if err != nil { 93 return errors.Wrap(err, "error getting stdout pipe for tar command") 94 } 95 96 errBuf := bytes.NewBuffer(nil) 97 tarCmd.Stderr = errBuf 98 tarCmd.Start() 99 defer tarCmd.Wait() 100 101 resp, err := client.ImageLoad(ctx, out, true) 102 if err != nil { 103 return errors.Wrap(err, "failed to load frozen images") 104 } 105 defer resp.Body.Close() 106 fd, isTerminal := term.GetFdInfo(os.Stdout) 107 return jsonmessage.DisplayJSONMessagesStream(resp.Body, os.Stdout, fd, isTerminal, nil) 108 } 109 110 func pullImages(ctx context.Context, client client.APIClient, images []string) error { 111 cwd, err := os.Getwd() 112 if err != nil { 113 return errors.Wrap(err, "error getting path to dockerfile") 114 } 115 dockerfile := os.Getenv("DOCKERFILE") 116 if dockerfile == "" { 117 dockerfile = "Dockerfile" 118 } 119 dockerfilePath := filepath.Join(filepath.Dir(filepath.Clean(cwd)), dockerfile) 120 pullRefs, err := readFrozenImageList(dockerfilePath, images) 121 if err != nil { 122 return errors.Wrap(err, "error reading frozen image list") 123 } 124 125 var wg sync.WaitGroup 126 chErr := make(chan error, len(images)) 127 for tag, ref := range pullRefs { 128 wg.Add(1) 129 go func(tag, ref string) { 130 defer wg.Done() 131 if err := pullTagAndRemove(ctx, client, ref, tag); err != nil { 132 chErr <- err 133 return 134 } 135 }(tag, ref) 136 } 137 wg.Wait() 138 close(chErr) 139 return <-chErr 140 } 141 142 func pullTagAndRemove(ctx context.Context, client client.APIClient, ref string, tag string) error { 143 resp, err := client.ImagePull(ctx, ref, types.ImagePullOptions{}) 144 if err != nil { 145 return errors.Wrapf(err, "failed to pull %s", ref) 146 } 147 defer resp.Close() 148 fd, isTerminal := term.GetFdInfo(os.Stdout) 149 if err := jsonmessage.DisplayJSONMessagesStream(resp, os.Stdout, fd, isTerminal, nil); err != nil { 150 return err 151 } 152 153 if err := client.ImageTag(ctx, ref, tag); err != nil { 154 return errors.Wrapf(err, "failed to tag %s as %s", ref, tag) 155 } 156 _, err = client.ImageRemove(ctx, ref, types.ImageRemoveOptions{}) 157 return errors.Wrapf(err, "failed to remove %s", ref) 158 159 } 160 161 func readFrozenImageList(dockerfilePath string, images []string) (map[string]string, error) { 162 f, err := os.Open(dockerfilePath) 163 if err != nil { 164 return nil, errors.Wrap(err, "error reading dockerfile") 165 } 166 defer f.Close() 167 ls := make(map[string]string) 168 169 scanner := bufio.NewScanner(f) 170 for scanner.Scan() { 171 line := strings.Fields(scanner.Text()) 172 if len(line) < 3 { 173 continue 174 } 175 if !(line[0] == "RUN" && line[1] == "./contrib/download-frozen-image-v2.sh") { 176 continue 177 } 178 179 for scanner.Scan() { 180 img := strings.TrimSpace(scanner.Text()) 181 img = strings.TrimSuffix(img, "\\") 182 img = strings.TrimSpace(img) 183 split := strings.Split(img, "@") 184 if len(split) < 2 { 185 break 186 } 187 188 for _, i := range images { 189 if split[0] == i { 190 ls[i] = img 191 break 192 } 193 } 194 } 195 } 196 return ls, nil 197 }