Exemple #1
0
// StoreImage stores file system layer data for the given image to the
// image's registered storage driver. Image metadata is stored in a file
// at the specified root directory. This function also computes the TarSum
// of `layerData` (currently using tarsum.dev).
func StoreImage(img *Image, layerData archive.ArchiveReader, root string) error {
	// Store the layer
	var (
		size        int64
		err         error
		driver      = img.graph.Driver()
		layerTarSum tarsum.TarSum
	)

	// If layerData is not nil, unpack it into the new layer
	if layerData != nil {
		// If the image doesn't have a checksum, we should add it. The layer
		// checksums are verified when they are pulled from a remote, but when
		// a container is committed it should be added here.
		if img.Checksum == "" {
			layerDataDecompressed, err := archive.DecompressStream(layerData)
			if err != nil {
				return err
			}
			defer layerDataDecompressed.Close()

			if layerTarSum, err = tarsum.NewTarSum(layerDataDecompressed, true, tarsum.VersionDev); err != nil {
				return err
			}

			if size, err = driver.ApplyDiff(img.ID, img.Parent, layerTarSum); err != nil {
				return err
			}

			img.Checksum = layerTarSum.Sum(nil)
		} else if size, err = driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
			return err
		}

	}

	img.Size = size
	if err := img.SaveSize(root); err != nil {
		return err
	}

	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
	if err != nil {
		return err
	}

	defer f.Close()

	return json.NewEncoder(f).Encode(img)
}
Exemple #2
0
// StoreImage stores file system layer data for the given image to the
// image's registered storage driver. Image metadata is stored in a file
// at the specified root directory. This function also computes the TarSum
// of `layerData` (currently using tarsum.dev).
func StoreImage(img *Image, layerData archive.ArchiveReader, root string) error {
	// Store the layer
	var (
		size        int64
		err         error
		driver      = img.graph.Driver()
		layerTarSum tarsum.TarSum
	)

	// If layerData is not nil, unpack it into the new layer
	if layerData != nil {
		layerDataDecompressed, err := archive.DecompressStream(layerData)
		if err != nil {
			return err
		}

		defer layerDataDecompressed.Close()

		if layerTarSum, err = tarsum.NewTarSum(layerDataDecompressed, true, tarsum.VersionDev); err != nil {
			return err
		}

		if size, err = driver.ApplyDiff(img.ID, img.Parent, layerTarSum); err != nil {
			return err
		}

		checksum := layerTarSum.Sum(nil)

		if img.Checksum != "" && img.Checksum != checksum {
			log.Warnf("image layer checksum mismatch: computed %q, expected %q", checksum, img.Checksum)
		}

		img.Checksum = checksum
	}

	img.Size = size
	if err := img.SaveSize(root); err != nil {
		return err
	}

	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
	if err != nil {
		return err
	}

	defer f.Close()

	return json.NewEncoder(f).Encode(img)
}
Exemple #3
0
func copyFiles(b *Build, args []string, cmdName string) (s State, err error) {

	s = b.state

	if len(args) < 2 {
		return s, fmt.Errorf("Invalid %s format - at least two arguments required", cmdName)
	}

	var (
		tarSum   tarsum.TarSum
		src      = args[0 : len(args)-1]
		dest     = filepath.FromSlash(args[len(args)-1]) // last one is always the dest
		u        *upload
		excludes = s.NoCache.Dockerignore
	)

	// If destination is not a directory (no trailing slash)
	hasTrailingSlash := strings.HasSuffix(dest, string(os.PathSeparator))
	if !hasTrailingSlash && len(src) > 1 {
		return s, fmt.Errorf("When using %s with more than one source file, the destination must be a directory and end with a /", cmdName)
	}

	if !filepath.IsAbs(dest) {
		dest = filepath.Join(s.Config.WorkingDir, dest)
		// Add the trailing slash back if we had it before
		if hasTrailingSlash {
			dest += string(os.PathSeparator)
		}
	}

	if u, err = makeTarStream(b.cfg.ContextDir, dest, cmdName, src, excludes, b.urlFetcher); err != nil {
		return s, err
	}

	// skip COPY if no files matched
	if len(u.files) == 0 {
		log.Infof("| No files matched")
		return s, nil
	}

	log.Infof("| Calculating tarsum for %d files (%s total)", len(u.files), units.HumanSize(float64(u.size)))

	if tarSum, err = tarsum.NewTarSum(u.tar, true, tarsum.Version1); err != nil {
		return s, err
	}
	if _, err = io.Copy(ioutil.Discard, tarSum); err != nil {
		return s, err
	}
	u.tar.Close()

	// TODO: useful commit comment?

	message := fmt.Sprintf("%s %s to %s", cmdName, tarSum.Sum(nil), dest)
	s.Commit(message)

	// Check cache
	s, hit, err := b.probeCache(s)
	if err != nil {
		return s, err
	}
	if hit {
		return s, nil
	}

	origCmd := s.Config.Cmd
	s.Config.Cmd = []string{"/bin/sh", "-c", "#(nop) " + message}

	if s.NoCache.ContainerID, err = b.client.CreateContainer(s); err != nil {
		return s, err
	}

	s.Config.Cmd = origCmd

	// We need to make a new tar stream, because the previous one has been
	// read by the tarsum; maybe, optimize this in future
	if u, err = makeTarStream(b.cfg.ContextDir, dest, cmdName, src, excludes, b.urlFetcher); err != nil {
		return s, err
	}

	// Copy to "/" because we made the prefix inside the tar archive
	// Do that because we are not able to reliably create directories inside the container
	if err = b.client.UploadToContainer(s.NoCache.ContainerID, u.tar, "/"); err != nil {
		return s, err
	}

	return s, nil
}