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  }