Beispiel #1
0
func getParent(file *os.File, imgID string, debug log.Logger) (string, error) {
	var parent string

	_, err := file.Seek(0, 0)
	if err != nil {
		return "", fmt.Errorf("error seeking file: %v", err)
	}

	jsonPath := filepath.Join(imgID, "json")
	parentWalker := func(t *tarball.TarFile) error {
		if filepath.Clean(t.Name()) == jsonPath {
			jsonb, err := ioutil.ReadAll(t.TarStream)
			if err != nil {
				return fmt.Errorf("error reading layer json: %v", err)
			}

			var dockerData types.DockerImageData
			if err := json.Unmarshal(jsonb, &dockerData); err != nil {
				return fmt.Errorf("error unmarshaling layer data: %v", err)
			}

			parent = dockerData.Parent
		}

		return nil
	}

	tr := tar.NewReader(file)
	if err := tarball.Walk(*tr, parentWalker); err != nil {
		return "", err
	}

	debug.Printf("Layer %q depends on layer %q", imgID, parent)
	return parent, nil
}
Beispiel #2
0
// getAncestry computes an image ancestry, returning an ordered list
// of dependencies starting from the topmost image to the base.
// It checks for dependency loops via duplicate detection in the image
// chain and errors out in such cases.
func getAncestry(file *os.File, imgID string, debug log.Logger) ([]string, error) {
	var ancestry []string
	deps := make(map[string]bool)

	curImgID := imgID

	var err error
	for curImgID != "" {
		if deps[curImgID] {
			return nil, fmt.Errorf("dependency loop detected at image %q", curImgID)
		}
		deps[curImgID] = true
		ancestry = append(ancestry, curImgID)
		debug.Printf("Getting ancestry for layer %q", curImgID)
		curImgID, err = getParent(file, curImgID, debug)
		if err != nil {
			return nil, err
		}
	}
	return ancestry, nil
}